我知道异步编程多年来已经发生了很多变化。令我感到困惑的是,我在34岁的时候就让自己生锈了,但是我指望着StackOverflow可以使我快速入门。
我想做的是在一个单独的线程上管理“工作”队列,但是每次只能处理一个项目。我想在此线程上发布工作,它不需要将任何内容传递回调用方。当然,我可以简单地启动一个新Thread
对象,并Queue
使用睡眠,中断,等待句柄等使其在共享对象上循环。但是我知道从那以后情况已经变得更好。我们有BlockingCollection
,Task
,async
/ await
,更不用提的NuGet包,可能抽象了很多的。
我知道,“什么是最好的...”问题通常会被忽略,因此我将通过说“最好使用什么是...”的方式来改写它,最好使用内置的.NET机制来完成类似的工作。但是,如果第三方NuGet程序包简化了一堆事情,那也是一样。
我考虑了一个TaskScheduler
实例,其最大并发固定为1,但是到目前为止,似乎没有那么笨拙的方法了。
背景
具体来说,在这种情况下,我想做的是在Web请求期间将IP地理位置任务排队。同一IP可能会多次排队等待进行地理位置定位,但是该任务将知道如何检测到该IP,如果已经解决,则可以尽早退出。但是请求处理程序将把这些() => LocateAddress(context.Request.UserHostAddress)
调用放入队列中,并让该LocateAddress
方法处理重复的工作检测。我使用的地理位置API不喜欢被请求轰炸,这就是为什么我想一次将其限制为单个并发任务。但是,如果允许该方法通过简单的参数更改轻松地扩展到更多并发任务,那就太好了。
要创建异步单并行程度的工作队列,您可以简单地创建一个SemaphoreSlim
,将其初始化为1,然后await
在开始请求的工作之前使用获取该信号量的入队方法。
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();
}
}
}
当然,除了具有一个固定的并行度之外,只需将信号量初始化为其他数量即可。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句