ContinueWith任务完成前任务运行
背景信息:我正在尝试创建一个能够同时处理5个并发操作的单例类。每个操作由SomeAsyncMethod
表示。ContinueWith任务完成前任务运行
该方法存在于单例类中。
consumers
是ConcurrentDictionary<int,Task>
我的问题:由于某种原因,ContinueWith
委托SomeAsyncMethod
完成之前运行。我知道这种情况发生的原因是因为我有另一种方法,手表instance.Consumers.Count
- 在SomeAsyncMethod
完成之前计数为0
。
这是为什么?
public bool TryAddDequeueRequest()
{
if (instance.Consumers.Count < 5)
{
Task bogusTask;
Task newTask = new Task(SomeAsyncMethod);
//RUNS AFTER THE REQUEST IS COMPLETED
newTask.ContinueWith(t =>
{
instance.Consumers.TryRemove(t.Id, out bogusTask);
});
//WE ADD THE TASK TO QUEUE
instance.Consumers.TryAdd(newTask.Id, newTask);
//SET IT AND FORGET IT
newTask.Start();
return true;
}
else
return false;
}
SomeAsyncMethod
,如果它的名称的任何迹象,是一种异步方法,大概一个返回一个Task
。你正在创建一个新的任务start这个异步操作在另一个线程中。那Task
会在你完成时返回开始的异步操作,而不是当它启动的异步操作完成时。
虽然你可以解开任务,但更简单的选择是不把它包裹在第一位。呼吁通过异步方法返回的Task
延续:
SomeAsyncMethod().ContinueWith(t =>
{
instance.Consumers.TryRemove(t.Id, out bogusTask);
});
instance.Consumers.TryAdd(newTask.Id, newTask);
当然,如果你希望能够用一个固定的平行度进行异步操作的一些数量,有更简单的方法。您可以使用SemaphoreSlim
公平平凡创建任何固定的平行度的工作队列:
public class FixedParallelismQueue
{
private SemaphoreSlim semaphore;
public FixedParallelismQueue(int maxDegreesOfParallelism)
{
semaphore = new SemaphoreSlim(maxDegreesOfParallelism);
}
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();
}
}
}
啊!让我尝试一下。 – 2014-09-05 20:31:22
SephamoreSlim块。 '当计数到零时,对其中一个Wait方法的后续调用会阻塞,直到其他线程释放信号为止。# – 2014-09-05 20:38:18
@SimchaKhabinsky好东西我没有叫'Wait',那不是。这段代码不会阻塞,它完全是异步的。 – Servy 2014-09-05 20:39:03
由于SomeAsyncMethod
是异步的,它完成了自己的任务前返回。
如果你有以上的SomeAsyncMethod
代码控制,然后重构它是同步的(没有await
/async
),或者如果已经有一个非异步版本,那么就使用它。
如果你没有在该方法的代码控制,你可以等待它周围的任务,然后再继续完成:
Task newTask = new Task(()=>{ SomeAsyncMethod().Wait(); });
你怎么知道它尚未完成? – 2014-09-05 20:20:52
添加了详细信息。 (我知道发生这种情况的原因是因为我有另一种方法来监视instance.Consumers.Count - 在SomeAsyncMethod完成之前计数为0.) – 2014-09-05 20:21:20
'SomeAsyncMethod'调用某些服务并更新数据库。全部通过'async'和'await'操作完成。 – 2014-09-05 20:22:29