问题描述
我知道异步编程已经看到了很多年来的许多变化。我有点尴尬,我让自己在34岁的时候生锈了,但我指望StackOverflow带给我速度。
我是什么试图做的是在单独的线程上管理工作的队列,但是这样一次只处理一个项目。我想在这个线程的工作,它不需要传递任何回调用者。当然,我可以简单地创建一个新的 Thread
对象,并让它循环共享 Queue
对象,使用睡眠,中断,等待句柄等等,但我知道事情从那以后变得更好。我们有 BlockingCollection
,任务
, async
/ await
,更不用说NuGet包可能抽象了很多。
我知道 问题通常被皱眉,所以我将改写它说:什么是目前推荐...的方式来完成类似这样使用内置的.NET机制。但是如果第三方NuGet包简化了一堆东西,它也是一样。
我考虑了一个 TaskScheduler
实例具有固定的最大并发性为1,但似乎现在可能是一个更少的笨重的方式来做这个。
背景 >
具体来说,我想在这种情况下做的是在Web请求期间对IP地理位置任务排队。相同的IP可能会多次排队等待地理位置,但任务将知道如何检测到,如果已经解决,则提前跳过。但是请求处理程序只是要抛出这些()=> LocateAddress(context.Request.UserHostAddress)
调用到队列中,并让 LocateAddress
方法处理重复工作检测。我使用的geolocation API不喜欢被请求轰炸,这就是为什么我想限制在一个单一的并行任务。
如果可以通过简单的参数更改轻松扩展到更多并发任务,创建一个异步单程并行度队列的工作你可以简单地创建一个 SemaphoreSlim
,初始化为一个,然后使用enqueing方法 await
public class TaskQueue
{
private SemaphoreSlim semaphore;
public TaskQueue()
{
semaphore = new SemaphoreSlim(1);
}
public async任务< T> Enqueue< T>(Func< Task< T>> taskGenerator)
{
await semaphore.WaitAsync
try
{
return await taskGenerator();
}
finally
{
semaphore.Release();
}
}
public async任务入队(Func< Task> taskGenerator)
{
await semaphore.WaitAsync
try
{
await taskGenerator();
}
finally
{
semaphore.Release();
}
}
}
当然,固定并行度除了一个简单的初始化信号量到一些其他数字。
I know that asynchronous programming has seen a lot of changes over the years. I'm somewhat embarrassed that I let myself get this rusty at just 34 years old, but I'm counting on StackOverflow to bring me up to speed.
What I am trying to do is manage a queue of "work" on a separate thread, but in such a way that only one item is processed at a time. I want to post work on this thread and it doesn't need to pass anything back to the caller. Of course I could simply spin up a new Thread
object and have it loop over a shared Queue
object, using sleeps, interrupts, wait handles, etc. But I know things have gotten better since then. We have BlockingCollection
, Task
, async
/await
, not to mention NuGet packages that probably abstract a lot of that.
I know that "What's the best..." questions are generally frowned upon so I'll rephrase it by saying "What is the currently recommended..." way to accomplish something like this using built-in .NET mechanisms preferably. But if a third party NuGet package simplifies things a bunch, it's just as well.
I considered a TaskScheduler
instance with a fixed maximum concurrency of 1, but seems there is probably a much less clunky way to do that by now.
Background
Specifically, what I am trying to do in this case is queue an IP geolocation task during a web request. The same IP might wind up getting queued for geolocation multiple times, but the task will know how to detect that and skip out early if it's already been resolved. But the request handler is just going to throw these () => LocateAddress(context.Request.UserHostAddress)
calls into a queue and let the LocateAddress
method handle duplicate work detection. The geolocation API I am using doesn't like to be bombarded with requests which is why I want to limit it to a single concurrent task at a time. However, it would be nice if the approach was allowed to easily scale to more concurrent tasks with a simple parameter change.
解决方案 To create an asynchronous single degree of parallelism queue of work you can simply create a SemaphoreSlim
, initialized to one, and then have the enqueing method await
on the acquisition of that semaphore before starting the requested work.
public class TaskQueue
{
private SemaphoreSlim semaphore;
public TaskQueue()
{
semaphore = new SemaphoreSlim(1);
}
public async Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
{
await semaphore.WaitAsync();
try
{
return await taskGenerator();
}
finally
{
semaphore.Release();
}
}
public async Task Enqueue(Func<Task> taskGenerator)
{
await semaphore.WaitAsync();
try
{
await taskGenerator();
}
finally
{
semaphore.Release();
}
}
}
Of course, to have a fixed degree of parallelism other than one simply initialize the semaphore to some other number.
这篇关于.NET中的最佳方式来管理单独(单个)线程上的任务队列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!