【发布时间】:2020-09-24 19:35:43
【问题描述】:
我有一个类的两个实例,它们创建一个 UDP 套接字来接收来自 UDP 客户端的数据。如果其中一个实例抛出异常,我想立即在更高层处理它。在我的程序中,它们以await Task.WhenAll(recv1.StartAsync(), recv2.StartAsync) 开头。但是,这会在引发第一个异常之前等待所有任务完成。有关如何解决此问题的任何想法?
static async Task Main(string[] args)
{
var udpReceiver1 = new UdpReceiver(localEndpoint1);
var udpReceiver2 = new UdpReceiver(localEndpoint2);
var cts = new CancellationTokenSource();
try
{
await Task.WhenAll(udpReceiver1.StartAsync(cts.Token), udpReceiver2.StartAsync(cts.Token));
}
catch (Exception e)
{
// Handle Exception...
cts.Cancel();
}
}
class UdpReceiver
{
public UdpReceiver(IPEndPoint endpoint)
{
udpClient = new UdpClient(endpoint);
}
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
while (!cancellationToken.IsCancellationRequested)
{
var result = await ReceiveAsync(cancellationToken);
var message = Encoding.UTF8.GetString(result.Buffer);
Trace.WriteLine($"UdpClient1 received message:{Encoding.UTF8.GetString(result.Buffer)}");
// throw new Exception("UdpClient1 raising exception");
}
}
}
private async Task<UdpReceiveResult> ReceiveAsync(CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<UdpReceiveResult>();
using (cancellationToken.Register(() => tcs.TrySetCanceled(), false))
{
var task = udpClient.ReceiveAsync();
var completedTask = await Task.WhenAny(task, tcs.Task);
var result = await completedTask.ConfigureAwait(false);
return result;
}
}
private UdpClient udpClient;
}
更新 1: Task.WhenAny 将是一个可行的解决方案。谢谢@CamiloTerevinto
try
{
await await Task.WhenAny(udpReceiver1.StartAsync(cts.Token), udpReceiver2.StartAsync(cts.Token));
}
catch (Exception e)
{
// Handle Exception...
cts.Cancel();
}
更新 2:为了对所有任务进行更细粒度的异常处理,我会使用 @Servy 提出的我自己改编的 Task.WhenAll 实现。
【问题讨论】:
-
嗯,
Task.WhenAll正是让你等待所有个任务。您可以使用Task.WhenAny,但需要自己处理非故障 -
如果实例失败,您希望发生什么?你想处理这个错误,然后忽略其他正在运行的实例而终止进程吗?
-
两个实例都应该在异常情况下正常终止
-
我认为您应该在问题中包含您希望两个实例都正常终止的问题。这是回答这个问题的重要信息。
标签: c# async-await task-parallel-library