【发布时间】:2017-07-31 16:13:09
【问题描述】:
我有一个使用 TPL 的 C# WinForms (.NET 4.5.2) 应用程序。该工具有一个同步函数,它被传递给任务工厂X 的次数(使用不同的输入参数),其中X 是用户在开始该过程之前声明的数字。任务启动并存储在List<Task>。
假设用户输入了5,我们在async 按钮点击处理程序中有这个:
for (int i = 0; i < X; i++)
{
var progress = Progress(); // returns a new IProgress<T>
var task = Task<int>.Factory.StartNew(() => MyFunction(progress), TaskCreationOptions.LongRunning);
TaskList.Add(task);
}
每个 progress 实例都会更新 UI。
现在,一旦完成一项任务,我就想启动一个新任务。本质上,该进程应该无限期地运行,在任何给定时间运行X 任务,除非用户通过 UI 取消(我将为此使用取消令牌)。我尝试使用以下方法来实现这一点:
while (TaskList.Count > 0)
{
var completed = await Task.WhenAny(TaskList.ToArray());
if (completed.Exception == null)
{
// report success
}
else
{
// flatten AggregateException, print out, etc
}
// update some labels/textboxes in the UI, and then:
TaskList.Remove(completed);
var task = Task<int>.Factory.StartNew(() => MyFunction(progress), TaskCreationOptions.LongRunning);
TaskList.Add(task);
}
这会使 UI 陷入困境。有没有更好的方法来实现此功能,同时保持 UI 响应?
在 cmets 中提出了使用 TPL 数据流的建议,但由于时间限制和规格,欢迎使用替代解决方案
更新
我不确定进度报告是否有问题?这是它的样子:
private IProgress<string> Progress()
{
return new Progress<string>(msg =>
{
txtMsg.AppendText(msg);
});
}
【问题讨论】:
-
你有什么理由不使用专门的工具来完成这项任务吗?您的场景正是 TPL Dataflow 的设计目的。
-
是的,我第二个 Kirill - TPL 数据流听起来很适合这个。
-
时间限制、项目规范和不了解 Dataflow(无论如何都会阅读并提出建议,谢谢)
标签: c# winforms async-await task-parallel-library