我正在以下列方式在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()是一项长期运作。
答案 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
上的await
和Task
,不要阻止Task.Wait()
:< / p>
public async void SoneEventHandler(object sender, EventArgs e)
{
foreach (var item in items)
{
var result = await Task.Run(() => DoWork());
// Update UI
}
}