取消task.delay无例外或使用异常来控制流量?

xar*_*tal 7 c# asynchronous exception-handling task-parallel-library async-await

我不确定在代码中对事件作出反应的两种可能性.大多数情况下,我担心哪一个需要更少的资源.我有一个观察者注册的方法eventproducer.如果eventproducer返回某个东西,则该方法退出并且该方法的调用者再次启动该方法(您可以将其视为一种长轮询).

eventproducer有时触发大量每秒的事件,有时休息几分钟.

第一种方法是等待500毫秒的延迟,然后检查是否有东西返回或以其他方式(直到超时5分钟)再次延迟500毫秒.

eventProducer.RegisterListener((events)=>{evList.Add(events)});
while(evList.Count=0 && !TimeOut){
    await Task.Delay(500);}
eventProducer.UnRegister(...);
// return evList, method gets recalled immediately
Run Code Online (Sandbox Code Playgroud)

第二种方法是使用a CancellationToken.如果eventproducer产生某些东西,则CancellationTokenSource取消源.在等待的方法中Task.Delay(5min, cancellationToken).

eventProducer.RegisterListener((events)=>{evList.Add(events);
                                          cancelSource.Cancel();}
try
{
     await Task.Delay(5min, cancellationToken)
}
catch(TaskCanceledException){//nothing to do};
eventProducer.UnRegister(...);
// return evList, method gets recalled immediately
Run Code Online (Sandbox Code Playgroud)

第二种方法的优点是,如果生产者生产某种东西,并且我们不必在循环中等待和唤醒,该方法立即返回.

但是,每当制作人产生某种东西时,第二种方法TaskCanceledException就是抛出.我担心这会比清醒更能影响系统负载,等待每500毫秒,尤其是当eventproducer产生大量事件时.

我是否过高估计抛出和捕获异常的成本?有没有办法取消Task.Delay一个CancellationToken但没有投掷TaskCanceledException?IE之类的东西task.setComplete

i3a*_*non 15

如果你想要一个类似于取消给你的即时通知,但没有例外,你可以简单地使用TaskCompletionSource.

TaskCompletionSource是你如何创建一个承诺任务.您将从Task酒店获得一项未完成的任务,然后您完成(或取消)SetResult.您可以使用它来实际传递结果本身:

var tcs = new TaskCompletionSource<Events>();
eventProducer.RegisterListener(events => tcs.SetResult(events));

var result = await tcs.Task;
eventProducer.UnRegister(...);
Run Code Online (Sandbox Code Playgroud)

此解决方案没有任何例外,也不使用不必要的轮询


回答您的具体问题:

我是否过高估计抛出和捕获异常的成本?

大概.你需要测试并证明它确实是一个问题.

有没有办法取消Task.Delay与CancellationToken但没有投掷TaskCanceledException

是.添加一个空的延续:

var delayTask = Task.Delay(1000, cancellationToken);
var continuationTask = delayTask.ContinueWith(task => { });
await continuationTask;
Run Code Online (Sandbox Code Playgroud)

  • 使用“await Task.Delay(1000, cancelToken).ContinueWith(task =&gt; { });”时,为什么不再抛出任务取消异常?在我为此进行 try-catch 之前,框架是否仍然需要在内部处理 catch 和处理异常,或者它不会首先抛出异常? (2认同)
  • @Snellface`Task.Delay`任务仍然被取消,并且如果您等待它仍然会引发异常。但是您没有等待它..您正在等待什么都不做的延续。由于它不执行任何操作且没有CancellationToken,因此不会引发任何异常。 (2认同)
  • @Snellface 在这种情况下实际上没有例外..但对于“Task.Delay”以外的其他东西可能会有。等待已取消的任务会引发异常,但创建已取消的任务不需要异常。想象一下“Task.Delay”方法返回一个TaskCompletionSource,而不是调用“tcs.SetResult”,而是使用“tcs.SetCanceled”。这样,“delayTask”就会被取消,等待它会抛出异常,而任务本身不会捕获任何异常。 (2认同)