Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 取消任务。是否无故延迟或使用异常控制流程?_C#_Asynchronous_Exception Handling_Async Await_Task Parallel Library - Fatal编程技术网

C# 取消任务。是否无故延迟或使用异常控制流程?

C# 取消任务。是否无故延迟或使用异常控制流程?,c#,asynchronous,exception-handling,async-await,task-parallel-library,C#,Asynchronous,Exception Handling,Async Await,Task Parallel Library,我不确定对代码中的事件做出反应的两种可能性。我最关心的是哪一个需要更少的资源。 我有一个方法,其中一个观测者注册到eventproducer。如果eventproducer返回某个内容,则该方法退出,并且该方法的调用方再次启动该方法(您可以将其视为一种长轮询) eventproducer有时每秒触发大量事件,有时会暂停几分钟 第一种方法是等待500毫秒的延迟,然后检查是否有返回的内容(直到超时5分钟)再次延迟500毫秒 eventProducer.RegisterListener((events

我不确定对代码中的事件做出反应的两种可能性。我最关心的是哪一个需要更少的资源。 我有一个方法,其中一个观测者注册到
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
第二种方法是使用
CancellationToken
。如果
eventproducer
生成某些内容,则
CancellationTokenSource
将取消该源。在方法中,我等待Task.Delay(5分钟,cancellationToken)

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

但是,对于第二种方法,每当生产者生成某些内容时,就会抛出一个
TaskCanceledException
。我担心这会比每500毫秒唤醒和等待对系统负载的影响更大,尤其是当
eventproducer
产生大量事件时


我是否高估了抛出和捕获异常的成本?有没有办法取消
任务。使用
CancellationToken
延迟
,但不抛出
TaskCanceledException
?例如,类似于
task.setComplete

如果您希望获得与取消通知类似的即时通知,但没有例外,您只需使用
TaskCompletionSource

TaskCompletionSource
是创建承诺任务的方式。您从
任务
属性中获得一个未完成的任务,然后使用
设置结果
完成它(或取消)。您可以使用它来实际传递结果本身:

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

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

您可以使用
\u cancellationToken.WaitHandle.WaitOne(超时以毫秒为单位)取而代之。它会在提供的超时后返回,或者在触发取消令牌时立即返回,而不会引发异常。

谢谢,TaskCompletionSource与我要查找的完全一样!当使用“wait Task.Delay(1000,cancellationToken).ContinueWith(Task=>{});”时,为什么它不再抛出Task cancelled异常?在我尝试捕获之前,框架是否仍然需要在内部处理捕获并处理异常,还是不首先抛出异常?@snell面对
任务。延迟
任务仍然被取消,如果等待它,它仍然会抛出异常。但你不是在等待。。您正在等待一个没有任何作用的继续。因为它不做任何事情,也没有CancellationToken,所以它不能抛出任何异常。@i3arnon因此,在很小的程度上,使用TaskCompletionSource可能会更有效?我第一次听说它是在这个QA中,所以我对它相当陌生。在我看来,从语义上来说,取消延迟比提前完成延迟更重要,但是,如果取消的成本比完成成本大得多,那么在这种特定情况下,语义差异可以忽略不计。我认为任务必须在内部处理异常也可能是错误的,但这就是我的理解,只是当我不等待时,我不需要捕捉它,对吗?@Snellface在这种情况下实际上没有异常。。但是对于任务以外的事情。延迟可能会出现。等待已取消的任务会引发异常,但创建已取消的任务不需要异常。假设
Task.Delay
方法返回TaskCompletionSource,而不是调用
tcs.SetResult
它使用
tcs.SetCanceled
。通过这种方式,
delayTask
被取消,等待它将抛出异常,而任务本身不会捕获任何异常。它只是“更长时间”的占位符,看起来不会等待调用,而是会阻止线程。
var tcs = new TaskCompletionSource<Events>();
eventProducer.RegisterListener(events => tcs.SetResult(events));

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