如何正确使用Task.WhenAll

Flo*_*ian 2 c# task async-await

关于这个问题(及其答案)我想使用TaskCompletionSource并Task.WhenAll等待任何任务首先返回True.所以我写了这个:

TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Task<bool> t0 = Task.Factory.StartNew<bool>(() => Find(paramA, paramB);
Task<bool> t1 = Task.Factory.StartNew<bool>(() => Find(paramC, paramD);
Task<bool> t2 = Task.Factory.StartNew<bool>(() => Find(paramE, paramF);
Task<bool> t3 = Task.Factory.StartNew<bool>(() => Find(paramG, paramH);

t0.ContinueWith(_ =>
{
    if (t0.Result)
        tcs.TrySetResult(t0.Result);
});

t1.ContinueWith(_ =>
{
    if (t1.Result)
        tcs.TrySetResult(t1.Result);
});

t2.ContinueWith(_ =>
{
    if (t2.Result)
        tcs.TrySetResult(t2.Result);
});

t3.ContinueWith(_ =>
{
    if (t3.Result)
        tcs.TrySetResult(t3.Result);
});

t4.ContinueWith(_ =>
{
    if (t4.Result)
        tcs.TrySetResult(t4.Result);
});

tcs.Task.Wait();
return tcs.Task.Result;
Run Code Online (Sandbox Code Playgroud)

当任何任务返回时,它工作正常true但是,如前面的答案所示:

棘手的一点是注意到所有任务都返回false ...在.NET 4.5中,通过Task.WhenAll创建另一个任务会相当容易.

所以我尝试玩,Task.WhenAll但我不想正确使用它...
我尝试过类似的东西:

tcs.Task.Wait(); // stays block here when all tasks return false
Task tr = Task.WhenAll(new Task[] { t0, t1, t2, t3, t4 });

if (tr.IsCompleted)
   return false;
else
return tcs.Task.Result;
Run Code Online (Sandbox Code Playgroud)

谢谢您的帮助

svi*_*ick 5

你想要等到你完成的两个任务中的一个,那Task.WaitAny()就是:

Task tr = Task.WhenAll(new Task[] { t0, t1, t2, t3, t4 });
Task.WaitAny(tcs.Task, tr);

if (tcs.Task.IsCompleted)
    return tcs.Task.Result;

return false;
Run Code Online (Sandbox Code Playgroud)

这也解决了代码中的竞争条件:即使返回了某个任务,也tr.IsCompleted可能是因为所有任务都可以同时完成.truetrue

作为替代方案,Task.WhenAny()如果您不想阻止,可以使用.

但是,由于您使用的是.Net 4.5,因此您可以awaitInterleaved()方法一起使用,该方法在完成任务时对任务进行排序:

async Task<bool> AnyTrue(IEnumerable<Task<bool>> tasks)
{
    foreach(var bucket in Interleaved(tasks))
    {
        if (await await bucket)
            return true;
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)