链接任务的正确方法

Anr*_*nri 5 c# multithreading task-parallel-library

我想链接Tasks,然后并行启动链.这个片段只是为了说明我的问题:

        var taskOrig = new Task(() => { });
        var task = taskOrig;
        foreach (var msg in messages)
        {
            task=task.ContinueWith(t => Console.WriteLine(msg));
        }
        taskOrig.Start();
Run Code Online (Sandbox Code Playgroud)

一切都很好,除了我内心的一点点完美主义者不喜欢先执行空方法() => { }.

有什么办法可以避免吗?

我明白它几乎不影响性能(除非你经常这样做),但仍然如此.性能在我的情况下很重要,因此检查每次迭代中是否存在任务都不是这样做的方法.

Ser*_*rvy 3

你可以这样做:

Task task = Task.FromResult<object>(null);
foreach (var msg in messages)
{
    task = task.ContinueWith(t => Console.WriteLine(msg));
}
Run Code Online (Sandbox Code Playgroud)

之前的解决方案在 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);
Run Code Online (Sandbox Code Playgroud)

(如果您愿意,可以移至SetResultforeach 循环之前。)

从技术上讲,这与您仍在添加更多内容时开始执行的延续不同。但这不太可能成为问题。

另一种选择是使用这样的东西:

public static Task ForEachAsync<T>(IEnumerable<T> items, Action<T> action)
{
    return Task.Factory.StartNew(() =>
    {
        foreach (T item in items)
        {
            action(item);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

一个示例用法是:

ForEachAsync(messages, msg => Console.WriteLine(msg));
Run Code Online (Sandbox Code Playgroud)