1

我有一個高吞吐量排隊安排,我接受Func<Task>並希望將其投影到Func<Task<System.Reactive.Unit>>以很好地適應下游Rx系統。將任務轉換爲任務<Unit>的最有效方法?

由於Unit.Default是唯一的價值,所以覺得這應該很容易,但我希望它儘可能高效。我希望以正確的方式通過原始Task的所有例外。

我目前的做法是:

public Task<Unit> QueueTaskRx(Func<Task> task) 
{ 
    Func<Task<Unit>> f = async() => 
    { 
     await task(); 
     return Unit.Default; 
    }; 

    return QueueTask(f); 
} 

,但我擔心的async/await

也許是其他的開銷,更有效的方法是:

public Task<Unit> QueueTaskRx(Func<Task> task) 
{ 
    Func<Task<Unit>> f =() => task().ContinueWith(_ => 
    { 
     // What other cases do I need to consider here?? 
     if (_.IsFaulted && _.Exception != null) 
      throw _.Exception.InnerException; 

     return Unit.Default; 
    }, TaskContinuationOptions.ExecuteSynchronously); 

    return QueueTask(f); 
} 

但是這並未」感覺安全和更復雜,分支等

有沒有人有更好的方法?

+2

*但我擔心async/await的開銷*爲什麼?你測試過這段代碼,發現編譯器生成的狀態機結構是最重要的開銷嗎? –

+0

@YuvalItzchakov謝謝 - 是的,我已經在一個緊密的循環中進行了測試,發現使用'async/await'和'ExecuteSynchronously'' ContinueWith'的速度慢了大約46%。 – jamespconnor

+2

也許您可以與我們分享您的測量代碼和性能結果。 –

回答

3

我會使用async/await,也增加了一個ConfigureAwait(false)

可以ContinueWith做到這一點,但是這將不僅節省您的時間真有些微小的量(像一個單一的逐位標誌檢查和單一的參考副本)。這將花費大量的複雜性:

  • ContinueWith應始終指定一個TaskScheduler
  • 除了例外,你應該處理取消,因爲這是由Task特別處理。

對於其他陷阱,看看我的博客Tour of Task系列(遺憾的是仍然不完整),在那裏我試圖枚舉使用「舊」的API可能會導致所有的問題(例如,ContinueWith)。

+0

調用'ConfigureAwait(false)' – jamespconnor

相關問題