取消task.delay无例外还是使用例外来控制流程? [英] Cancel task.delay without exception or use exception to control flow?

查看:187
本文介绍了取消task.delay无例外还是使用例外来控制流程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定对代码中的事件做出反应的两种可能性。通常,我担心的是哪一个需要更少的资源。
我有一个方法,将观察者注册到事件生产者。如果事件生产者返回某些内容,该方法将退出,并且该方法的调用者将再次启动该方法(您可以将其视为长时间轮询)。

I'm unsure about two possibilities to react to an event in my code. Mostly I'm concerned about which one needs less resources. I have a method with an observer registered to an eventproducer. If the eventproducer returns something, the method exits and the caller of the method starts the method again (you can think of it as a kind of a long polling).

事件生产者有时每秒触发大量事件,有时休息几分钟。

The eventproducer sometimes fires lots of events per seconds and sometimes rests for minutes.

第一种方法是等待500毫秒的延迟,然后检查是否有返回值,否则(直到5分钟超时)再次延迟500毫秒。 / p>

The first approach was to await a delay of 500ms and then check if there is something to return or otherwise (until a timeout of 5 minutes) again delay for 500ms.

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

第二种方法是使用 CancellationToken 。如果事件生产者产生了某些东西,则 CancellationTokenSource 会取消源。在方法中,我等待 Task.Delay(5min,cancelestToken)

The second approach was to use a CancellationToken. If the eventproducer produces something, the CancellationTokenSource cancels the source. And in the method I wait for 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

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

The advantages of the second approach are that the method immediately returns if the producer produces something and that we don't have to await and awake in a loop.

但是使用第二种方法,每当生产者产生某种东西时,都会抛出一个 TaskCanceledException 。我担心这可能比清醒对系统负载的影响更大,每500ms等待一次,尤其是

But with the second approach every time the producer produces something, a TaskCanceledException is thrown. I'm concerned that this could affect system load more than the awake and await every 500ms especially i times when the eventproducer produces lots of events.

Am我高估了引发和捕获异常的成本吗?有办法o使用 CancellationToken 取消 Task.Delay ,但不抛出 TaskCanceledException ?即像 task.setComplete 一样?

Am I overestimating the cost of throwing and catching an exception? And is there a way to cancel Task.Delay with a CancellationToken but without throwing a TaskCanceledException? I.E. something like task.setComplete?

推荐答案

如果要立即通知与取消操作类似,但没有例外,您可以简单地使用 TaskCompletionSource

If you want an immediate notification similar to what a cancellation gives you but without an exception you can simply use TaskCompletionSource.

TaskCompletionSource 是创建承诺任务的方式。您从 Task 属性中获得未完成的任务,并使用 SetResult 完成(或取消)该任务。您可以使用它实际传递结果本身:

TaskCompletionSource is how you create a promise task. You get an uncompleted task from the Task property and you complete it (or cancel) with SetResult. You can use it to actually pass on the result itself:

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

var result = await tcs.Task;
eventProducer.UnRegister(...);

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

This solution doesn't have any exceptions and doesn't use unnecessary polling

回答您的特定问题:


我高估了引发和捕获异常的成本?

Am I overestimating the cost of throwing and catching an exception?

可能是。您需要测试并证明这确实是一个问题。

Probably. You need to test and prove it's really an issue.


有没有办法用 CancellationToken 但不抛出 TaskCanceledException



Yes. Add an empty continuation:

var delayTask = Task.Delay(1000, cancellationToken);
var continuationTask = delayTask.ContinueWith(task => { });
await continuationTask;

这篇关于取消task.delay无例外还是使用例外来控制流程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆