1

背景信息:我正在尝试创建一个能够一次处理 5 个并发操作的单例类。每个操作由 表示SomeAsyncMethod


此方法存在于单例类中。

consumers是一个ConcurrentDictionary<int,Task>

我的问题:由于某种原因,ContinueWith委托在SomeAsyncMethod. 我知道发生这种情况的原因是因为我有另一种观察方法instance.Consumers.Count- 计数0SomeAsyncMethod完成之前。

这是为什么?

    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;
    }
4

2 回答 2

2

SomeAsyncMethod,如果它的名称有任何指示,它是一个异步方法,大概是一个返回 a 的方法Task。您正在创建一个新任务以在另一个线程中启动此异步操作。这Task将在您完成启动异步操作时返回,而不是在它启动的异步操作完成时返回。

虽然您可以解开任务,但更简单的选择是首先不将其包装。Task调用异步方法返回的延续:

SomeAsyncMethod().ContinueWith(t =>
{
    instance.Consumers.TryRemove(t.Id, out bogusTask);
});
instance.Consumers.TryAdd(newTask.Id, newTask);

当然,如果您希望能够以固定的并行化程度执行一些异步操作,还有更简单的方法。您可以使用 aSemaphoreSlim相当简单地创建任何固定并行化程度的工作队列:

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-05T20:28:49.030 回答
0

由于SomeAsyncMethod是异步的,它在完成自己的任务之前返回。

如果您可以控制代码,SomeAsyncMethod然后将其重构为同步(无await/ async),或者如果已经有非异步版本,那么就使用它。

如果您无法控制该方法的代码,您可以等待它在周围的任务中完成,然后再继续:

Task newTask = new Task(()=>{ SomeAsyncMethod().Wait(); });
于 2014-09-05T20:49:01.223 回答