并行执行任务

时间:2015-12-19 21:42:08

标签: c# .net asynchronous async-await task-parallel-library

好的,基本上我有一堆任务(10),我想同时启动所有任务并等待它们完成。完成后我想执行其他任务。我读了很多关于此的资源,但我无法为我的具体情况做好准备......

这是我目前所拥有的(代码已经简化):

public async Task RunTasks()
{
    var tasks = new List<Task>
    {
        new Task(async () => await DoWork()),
        //and so on with the other 9 similar tasks
    }


    Parallel.ForEach(tasks, task =>
    {
        task.Start();
    });

    Task.WhenAll(tasks).ContinueWith(done =>
    {
        //Run the other tasks
    });
}

//This function perform some I/O operations
public async Task DoWork()
{
    var results = await GetDataFromDatabaseAsync();
    foreach (var result in results)
    {
        await ReadFromNetwork(result.Url);
    }
}

所以我的问题是,当我等待任务完成WhenAll调用时,它告诉我所有任务都已结束,即使它们都没有完成。我尝试在Console.WriteLine中添加foreach,当我输入延续任务时,数据会从我之前未完成的Task中继续传入。

我在这里做错了什么?

3 个答案:

答案 0 :(得分:30)

您几乎不应该直接使用Task构造函数。在您的情况下,该任务仅触发您不能等待的实际任务。

您只需致电DoWork并取回任务,将其存储在列表中并等待所有任务完成。含义:

tasks.Add(DoWork());
// ...
await Task.WhenAll(tasks);

但是,异步方法会同步运行,直到达到未完成任务的第一个await为止。如果您担心该部分花费的时间过长,请使用Task.Run将其卸载到另一个ThreadPool主题,然后将那个任务存储在列表中:

tasks.Add(Task.Run(() => DoWork()));
// ...
await Task.WhenAll(tasks);

答案 1 :(得分:1)

DoWork方法是一种异步I / O方法。这意味着您不需要多个线程来执行其中的几个,因为大多数情况下该方法将异步等待I / O完成。一个线程足以做到这一点。

public async Task RunTasks()
{
    var tasks = new List<Task>
    {
        DoWork(),
        //and so on with the other 9 similar tasks
    };

    await Task.WhenAll(tasks);

    //Run the other tasks            
}

您应该never use the Task constructor创建一个新任务。要创建异步I / O任务,只需调用async方法即可。要创建将在线程池线程上执行的任务,请使用Task.Run。您可以阅读this article以获取Task.Run的详细说明以及其他创建任务的选项。

答案 2 :(得分:0)

还要在Task.WhenAll

周围添加一个try-catch块

注意:抛出System.AggregateException的一个实例,它充当一个或多个已发生的异常的包装器。这对于协调多个任务(如Task.WaitAll()和Task.WaitAny())的方法很重要,因此AggregateException能够包含已发生的正在运行的任务中的所有异常。

try
{ 
    Task.WaitAll(tasks.ToArray());  
}
catch(AggregateException ex)
{ 
    foreach (Exception inner in ex.InnerExceptions)
    {
    Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source));
    }
}