我想链接Task
,然后并行启动链。
这个片段只是为了说明我的问题:
var taskOrig = new Task(() => { });
var task = taskOrig;
foreach (var msg in messages)
{
task=task.ContinueWith(t => Console.WriteLine(msg));
}
taskOrig.Start();
一切都很好,除了我内心的一点点完美主义者并不喜欢先执行空方法() => { }
。
有什么办法可以避免吗?
我确实理解它几乎不会影响性能(除非你经常这样做),但仍然如此。在我的情况下,性能很重要,因此检查每次迭代中是否存在任务都不是实现它的方法。
答案 0 :(得分:3)
你可以这样做:
Task task = Task.FromResult<object>(null);
foreach (var msg in messages)
{
task = task.ContinueWith(t => Console.WriteLine(msg));
}
以前的解决方案在4.0中不起作用。在4.0中,您需要执行以下操作:
var tcs = new TaskCompletionSource<object>();
Task task = tcs.Task;
foreach (var msg in messages)
{
task = task.ContinueWith(t => Console.WriteLine(msg));
}
tcs.SetResult(null);
(如果您愿意,可以将SetResult
移到foreach循环之前。)
从技术上讲,当你还在添加更多时,延续将开始执行并不相同。但这不太可能成为问题。
另一种选择是使用这样的东西:
public static Task ForEachAsync<T>(IEnumerable<T> items, Action<T> action)
{
return Task.Factory.StartNew(() =>
{
foreach (T item in items)
{
action(item);
}
});
}
示例用法是:
ForEachAsync(messages, msg => Console.WriteLine(msg));
答案 1 :(得分:2)
这样做的一种方法是在循环中创建任务,如果它是null,但是你提供的代码看起来更适合我:
Task task = null;
foreach (var msg in messages)
{
if (task == null)
task = new Task(() => Console.WriteLine(msg))
else
task = task.ContinueWith(t => Console.WriteLine(msg));
}
task.Start();
答案 2 :(得分:1)
也许这就是:
if(messages.Length > 0)
{
Task task = new Task(t => Console.WriteLine(messages[0]));
for(int i = 1; i < messages.Length; i++)
{
task = task.ContinueWith(t => Console.WriteLine(messages[i]));
}
task.Start();
}