c#等待循环内的任务

时间:2016-03-25 21:09:17

标签: c# .net multithreading winforms task-parallel-library

我正在以下列方式在Windows窗体应用程序中使用TPL:

foreach (var item in items)
{
    task = Task<object>.Factory.StartNew (() => doWork());
    task.Wait();
    //update the UI using the result
}

我正在等待任务完成,因为我需要处理列表中的每个项目,但正如您想象的那样,这会导致我的UI线程中的锁定(UI冻结)。

我想知道如何以不锁定UI线程的方式实现它。

更新:我正在使用.NET Framework 4.5

感谢。

P.S DoWork()是一项长期运作。

2 个答案:

答案 0 :(得分:2)

创建事件处理程序async,并在代表线程池操作的任务上调用await。这将导致您的事件处理程序放弃对UI线程的控制,直到任务完成,然后继续更新UI并开始下一个任务。

private async void MyButton_Click(object sender, EventArgs e)
{
    foreach (var item in items)
    {
        // assuming C# 5 closure semantics
        await Task.Run(() => doWork(item));

        // update the UI using the result
    }
}

上述方法假定您要按顺序运行任务。如果要并行启动它们并按​​完成顺序处理结果,可以使用:

private async void MyButton_Click(object sender, EventArgs e)
{
    var tasks = items.Select(item => Task.Run(() => doWork(item))).ToList();
    while (tasks.Any())
    {
        var task = await Task.WhenAny(tasks);
        tasks.Remove(task);
        var result = await task;

        // update the UI using the result
    }
}

答案 1 :(得分:2)

你可以通过几种方式解决这个问题。

一个不是在线程池线程上执行列表中的每个项目,而是将整个foreach循环排在Task内,然后在结束时更新结果。

public async void SoneEventHandler(object sender, EventArgs e)
{
    var result = await Task.Run(() => items.Select(item => DoWork()).ToList());
    foreach (var item in items)
    {
        // Update UI
    }
}

如果您仍想处理线程池线程中的每个项目,请使用Task.Run上的awaitTask,不要阻止Task.Wait():< / p>

public async void SoneEventHandler(object sender, EventArgs e)
{
    foreach (var item in items)
    {
        var result = await Task.Run(() => DoWork());
        // Update UI
    }
}