2014-02-26 22 views
4

是否可以使用System.Threading.Task.Task創建可以取消的任務循環?如何創建可取消任務循環?

流程應以Task.Delay(xms)開始,然後繼續執行用戶定義的任務,然後繼續執行另一個Task.Delay(y ms)並從用戶定義的任務開始重複。

var result = Task.Delay(initialDelay) 
       .ContinueWith(t => dostuff..) 
       .ContinueWith what goes here? 

它甚至可以使用任務嗎?

我可以啓動一個計時器並完成它,但如果我需要取消,使用任務似乎是正確的方法,否?

回答

9

await使這個超級簡單:

public async Task TimedLoop(Action action, 
    CancellationToken token, TimeSpan delay) 
{ 
    while (true) 
    { 
     token.ThrowIfCancellationRequested(); 
     action(); 
     await Task.Delay(delay, token); 
    } 
} 

沒有async(但仍只使用TPL)這是一個有點混亂。我通常通過將本身附加到類型爲Task的變量的延續來解決此問題。這工作正常,但它可能需要一秒鐘來繞過它。如果沒有await,則只需使用Timer即可。

public Task TimedLoop(Action action, 
    CancellationToken token, TimeSpan delay) 
{ 
    //You can omit these two lines if you want the method to be void. 
    var tcs = new TaskCompletionSource<bool>(); 
    token.Register(() => tcs.SetCanceled()); 

    Task previous = Task.FromResult(true); 
    Action<Task> continuation = null; 
    continuation = t => 
    { 
     previous = previous.ContinueWith(t2 => action(), token) 
      .ContinueWith(t2 => Task.Delay(delay, token), token) 
      .Unwrap() 
      .ContinueWith(t2 => previous.ContinueWith(continuation, token)); 
    }; 
    previous.ContinueWith(continuation, token); 
    return tcs.Task; 
} 
+1

我也會將取消標記傳遞給'Delay'方法。 –

+0

@EliArbel編輯。 – Servy

+0

似乎是濫用迭代器來模擬異步的好用例。有一個庫。 – usr