2017-10-20 64 views
-2

我想用真正的同步方法創建一個類庫,所以我想避免實現一個只使用Task.Run來運行同步代碼的假異步方法。如何實現真正的異步方法?

我已經看到,一個方法是這樣:

public Task miMethodAsync() 
{ 
    TaskCompletionSource<bool> miTcs = new TaskCompletionSource<bool>(); 
    new Timer(_ => 
     { 
      for (Int64 i = 1; i < 10000000; i++) 
      { 
       //todo my long code 
      } 
      miTcs.SetResult(true); 
     }) 
     .Change(0, Timeout.Infinite); 

    return miTcs.Task; 
} 

該解決方案使用計時器返回的任務,然後在0毫秒後,它將運行在定時器中的代碼。

此解決方案不會創建新任務,因此它不會佔用線程表單線程池,因此可擴展性很好。但我認爲這個解決方案,使用定時器來運行同步代碼,這不是一個優雅的解決方案,所以我想知道我能夠實現一個真正的異步方法。

因爲這個解決方案還我可以有我的同步方法,只是實現這種方式ASYN方法:

public Task myMethodAsync() 
{ 
    TaskCompletionSource<bool> miTcs = new TaskCompletionSource<bool>(); 
    new Timer(_ => 
     { 
      myMethodSync(); 
      miTcs.SetResult(true); 
     }) 
     .Change(0, Timeout.Infinite); 

    return miTcs.Task; 
} 

但正如我的評論,我覺得這不是一個完美的解決方案,但實際上它似乎不是像我在Task.Run()方法內運行同步代碼時那樣的僞異步方法。

+0

如果計時器代碼在同一個線程中運行(並且這是一個UI線程)並且運行時間很長,它仍然會凍結UI。如果;然而,計時器會創建一個新的線程,通過使用計時器隱藏這個線程,您獲得了什麼? –

+3

只要同步方法正在運行,這將用盡一個線程。無論這是活動線程,UI線程還是線程池線程,都取決於您正在使用的.NET庫中名爲Timer的六個類中的哪一個,以及哪個線程調用myMethodAsync()。 –

+1

你可以詳細說明爲什麼你想在同步代碼中創建一個'async'包裝嗎?假設你閱讀引用的帖子[從你最後一個問題](https://stackoverflow.com/questions/46845005/is-it-really-a-bad-idea-to-use-threads-in-a-class-library )你知道這是一個壞主意。你是否正在履行「任務」返回界面?如果是,則返回'Task.FromResult'或'Task.CompletedTask',並再次讓客戶決定何時卸載該進程。沒有更多的細節,你會得到以前的建議,即[**不要做**](https://stackoverflow.com/a/32642687/7339946)。 – JSteward

回答

1

這些將同步代碼包裝到僞async方法中的包裝是沒有用的。推薦的方法不是創建任何這樣的包裝器,而是讓API用戶自己執行Task.Run(SyncMethod)。

查看詳細信息article