4

我不確定兩種可能性來對我的代碼中的事件做出反應。我主要關心哪一個人需要更少的資源。 我有一個觀察者註冊到eventproducer的方法。如果eventproducer返回某些內容,則此方法退出並且方法的調用者再次啓動該方法(您可以將其視爲一種長輪詢)。取消task.delay無例外或使用異常來控制流量?

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(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 

第二種方法的優點是,如果廠家生產的東西,我們不必等待,並在循環清醒的方法立即返回。

但隨着第二種方法每次生產者產生東西時,引發TaskCanceledException。我擔心這可能會影響系統負載超過清醒並等待每500ms,特別是當eventproducer產生大量事件時。

我是否高估了投擲和捕捉異常的成本?有沒有辦法取消Task.DelayCancellationToken但沒有投擲TaskCanceledException? I.E.像task.setComplete

+0

爲什麼五分鐘? – i3arnon

+0

它只是一個「更長時間」的佔位符 – xartal

回答

10

如果您希望立即發出類似於取消提示的通知,但沒有例外,您可以簡單地使用TaskCompletionSource

TaskCompletionSource是您如何創建承諾任務。您從Task屬性中獲得未完成的任務,並使用SetResult完成它(或取消)。你可以用它實際傳遞的結果本身:

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

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

這個解決方案沒有任何異常,並且不使用不必要的輪詢


爲了回答您的具體問題:

我是否高估了投擲和捕捉異常的成本?

也許。你需要測試並證明這確實是一個問題。

有沒有辦法取消Task.Delay與CancellationToken但沒有投擲TaskCanceledException

是。添加一個空的延續:

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

謝謝,TaskCompletionSource看起來完全像我在找的東西! – xartal

+1

當使用 「等待Task.Delay(1000,的CancellationToken).ContinueWith(任務=> {});」,爲什麼它不再拋出任務取消例外呢? 之前,我有一個try-catch爲此,該框架是否仍需要處理漁獲物和內部處理異常,或者它不符合這個首先拋出一個異常? – Snellface

+1

@Snellface Task_Delay任務仍然被取消,如果你等待它,它仍然會拋出一個異常。但是你並沒有等待它......你在等待一個什麼都不做的延續。由於它什麼也沒做,也沒有CancellationToken,所以不能拋出任何異常。 – i3arnon

-1

您可以改爲使用_cancellationToken.WaitHandle.WaitOne(timeout in milliseconds);。它在提供的超時之後返回,或者立即在取消令牌被觸發的情況下返回,而不會引發異常。

+0

這看起來像不會等待電話,而是會阻止該線程。 – mms