c# 在循环中等待任务
c# wait for a task inside a loop
我通过以下方式在 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() 是一个很长的 运行 操作。
创建事件处理程序 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
}
}
您可以通过多种方式解决此问题。
一种方法是不要在线程池线程上执行列表中的每个项目,而是将整个 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
上使用 Task.Run
和 await
,不要使用 Task.Wait()
阻塞:
public async void SoneEventHandler(object sender, EventArgs e)
{
foreach (var item in items)
{
var result = await Task.Run(() => DoWork());
// Update UI
}
}
我通过以下方式在 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() 是一个很长的 运行 操作。
创建事件处理程序 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
}
}
您可以通过多种方式解决此问题。
一种方法是不要在线程池线程上执行列表中的每个项目,而是将整个 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
上使用 Task.Run
和 await
,不要使用 Task.Wait()
阻塞:
public async void SoneEventHandler(object sender, EventArgs e)
{
foreach (var item in items)
{
var result = await Task.Run(() => DoWork());
// Update UI
}
}