背景信息:我正在尝试创建一个能够一次处理5个并发操作的单例类。每个操作都由SomeAsyncMethod
表示。
此方法位于单例类中。
consumers
是ConcurrentDictionary<int,Task>
我的问题:由于某种原因,ContinueWith
委托在SomeAsyncMethod
完成之前运行。我知道这种情况发生的原因是因为我有另一种观察instance.Consumers.Count
的方法 - 在0
完成之前计数为SomeAsyncMethod
。
为什么?
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;
}
答案 0 :(得分:2)
SomeAsyncMethod
,如果它的名称是任何指示,则是异步方法,可能是返回Task
的方法。您正在创建一个新任务,以便在另一个线程中启动此异步操作。完成启动异步操作后,Task
将返回,而不是在它开始的异步操作完成时。{/ p>
虽然您可以解开任务,但更简单的选择就是不首先将其包装起来。在异步方法返回的Task
上调用continuation:
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();
}
}
}
答案 1 :(得分:0)
由于SomeAsyncMethod
是异步的,因此它会在完成自己的任务之前返回。
如果您可以控制SomeAsyncMethod
的代码,那么将其重构为同步(无await
/ async
),或者如果已存在非异步版本,则只需用那个。
如果你无法控制方法的代码,你可以等待它完成周围的任务,然后再继续:
Task newTask = new Task(()=>{ SomeAsyncMethod().Wait(); });