WaitAll与WaitAny的区别

4

我对WaitAllWaitAny有点困惑。我试图获取异常,但当我使用WaitAll时,它返回异常,但当我使用WaitAny时,它不返回任何内容。而且必要的是,如果任何一个任务完成了,工作就完成了。 有没有WaitAny()的替代方法? WaitAllWhenAll是不同的,因为我不想让所有任务都完成。

try
{
    int i = 0;
    Task t1 = Task.Factory.StartNew(() =>
        {
            i = 2 * 4;
        });

    Task<int> t2 = Task.Factory.StartNew(() =>
        {
            int a = 0;
            int b = 100 / a;
            return 0;
        });

    Task[] tasks = new Task[] { t1, t2 };
    Task.WaitAny(tasks);
    //Task.WaitAll(tasks);// Working

}
catch (AggregateException ae)
{
    var message = ae.InnerException.Message;
    Console.WriteLine(message);
}
Console.ReadLine();

7
有什么混淆吗?你说过你想要等待任何一个任务完成。很有可能(但不保证)t1会在t2引发异常之前成功完成,所以你被告知 t1已经成功完成了,可以继续按照正常的流程进行。 - Damien_The_Unbeliever
同样的问题在这里:http://stackoverflow.com/q/29681272/613130 - xanatos
如果我必须使用WaitAny,那么如何处理异常?因为我需要在任何一个任务完成时立即结束工作。 - shaair
1
@Damien_The_Unbeliever 这并不完全正确,因为即使两个任务都会抛出异常 - WaitAny也不会抛出异常。因此,WaitAny并不能告诉您任务是否已成功完成,只是告诉您它已完成(这很可能意味着它失败了)。 - Evk
你可能会觉得这很有趣:如何等待一组任务并在第一个异常发生时停止等待? - Theodor Zoulias
显示剩余2条评论
3个回答

4
这被称为未观察到的异常,基本上意味着在任务并行库(TPL)线程池中新创建的线程中发生的异常不会被其他线程捕获,或者如上述链接所述:
引起未观察到的异常仍将导致引发UnobservedTaskException事件(不这样做将是一个破坏性的变化),但默认情况下进程不会崩溃。相反,在引发事件后,异常最终会被吞掉,无论事件处理程序是否观察到异常。
这意味着当使用WaitAny()时,如果其中一个任务完成而没有任何异常,则其他任务中的异常将不会被捕获。

我要补充一点,即使一个线程抛出异常而其他线程仍在“工作”,WaitAny() 仍然会“返回”。 - xanatos

3
也许您想要类似这样的东西。请注意,这使用了基于任务的异步模式
public static Task<Task[]> WhenAllOrFirstException(params Task[] tasks)
{
    var countdownEvent = new CountdownEvent(tasks.Length);
    var completer = new TaskCompletionSource<Task[]>();

    Action<Task> onCompletion = completed =>
        {
            if (completed.IsFaulted && completed.Exception != null)
            {
                completer.TrySetException(completed.Exception.InnerExceptions);
            }

            if(countdownEvent.Signal() && !completer.Task.IsCompleted)
            {
                completer.TrySetResult(tasks);
            }
        };

    foreach(var task in tasks)
    {
        task.ContinueWith(onCompletion)
    }

    return completer.Task;
}

不错。如果为这个方法制作扩展会更好。 - shaair
@SAL 但是,你想要扩展什么? - Jodrell
请注意,OP使用的是Task.WaitAny而不是Task.WhenAny - Evk
@Evk,我知道这一点,这就是为令我在开头段落中引用TAP的原因。我的观点是每个人都应该使用Task.WhenAny而不是Task.WaitAny - Jodrell

0

你的WaitAny实现会抛出错误,这取决于哪个任务先完成。 WaitAny不会等待较慢的任务(在大多数情况下是t2)完成-因此它不会从中获得异常。

更新

确实,WaitAny不会返回任何错误,如Task.WhenAny and Unobserved Exceptions所述


如果出现这种情况,但我不需要等待所有任务完成。如果一个任务出现异常,那么如何获取异常?垃圾回收会抛出异常吗? - shaair
无论哪个任务先完成,WaitAny都不会抛出异常。 - Evk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接