我想知道如何實現我自己的異步方法的最佳方式。我已閱讀this article,它說,將同步方法封裝到任務中並將其用作異步方法並不是一個好主意,因爲這種方式使用其他線程並使用更多資源,這就是我們想要避免使用異步的方法。如何以正確的方式實現我的異步方法?
在文章中使用TaskCompletionSource,但我不知道如何使用它。 TaskCompletionSource的目的是什麼?
我想知道如何實現我自己的異步方法的最佳方式。我已閱讀this article,它說,將同步方法封裝到任務中並將其用作異步方法並不是一個好主意,因爲這種方式使用其他線程並使用更多資源,這就是我們想要避免使用異步的方法。如何以正確的方式實現我的異步方法?
在文章中使用TaskCompletionSource,但我不知道如何使用它。 TaskCompletionSource的目的是什麼?
編寫async
方法的最佳資源是Task-based Asynchronous Pattern (TAP) document by Stephen Toub。該文件中的大部分信息現在是part of the official MSDN documentation。
如果你想要一個較短的(但仍然是徹底的)教程,我推薦自己的async
/await
intro blog post,還有其他幾個教程。一旦你瞭解了一下async
,下一個好資源是official async
/await
FAQ。
Channel9上還有很多很棒的async
視頻。當它仍然是CTP時,它們中的很多(大多數?)討論了async
,但是當它投入生產時很少進行設計更改。
要回答您的具體問題,請使用TaskCompletionSource
爲現有異步操作(例如,I/O操作,計時器或事件)創建一個Task
包裝。您不能執行由TaskCompletionSource
創建的Task
中的代碼;您應該使用Task.Run
在Task
中執行代碼。
在另一個async
方法(使用.NET 5.0 async
關鍵字)內調用方法很好。我不確定我完全理解你的問題,但請看下面的簡單例子。要出發int
與數之間顯示的質數,我們可以寫
async void DisplayPrimes()
{
int result = await GetPrimesCountAsync(2, 10000);
Console.WriteLine(result);
}
其中
Task<int> GetPrimesCountAsync(int start, int count)
{
return Task.Run(() =>
ParrallelEnumerable.Range(start, count).COunt(n =>
Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));
}
這裏async
修飾符告訴編譯器把等待作爲關鍵字,而不是一個標識符應任何含糊之處在該方法內出現。這確保了在C#5.0之前編寫的可能使用await作爲標識符的代碼仍然無錯地編譯。異步修飾符只能應用於返回void或Task
/Task<TResult>
的方法和lambda表達式。
在遇到await
表達式時,執行(通常)返回給調用者 - 而非像在使用yeild return
一樣。但是在返回之前,運行時會爲等待的任務附加一個延續,以確保當任務完成時,執行會跳回到繼續停止的方法中。我想你可以寫上面的方法,顯示編譯器將其轉換爲什麼
void DisplayPrimesCount()
{
var awaiter = GetPrimesCountAsync(2, 100000).GetAwaiter();
awaiter.OnCompleted(() =>
{
int result = awaiter.GetResult();
Console.WriteLine(result);
});
}
我希望這有助於。
編輯。這樣可以避免任務阻塞(這是很難說你的情況是什麼,你已經張貼任何代碼),你需要把你想創建「一個級別」
private async Task<bool> TestAsync()
{
return await Task.Run(() =>
{
// Do stuff non-blocking.
return true;
}).ConfigureAwait(continueOnCapturedContext:false);
}
TestAsync
這裏會把async
過程能夠通過在線程池線程而不是UI上下文上執行它的「return」語句來完成。這將立即返回給呼叫者,但請注意,但是,如果您繼續使用Task.Result
,則任何異常都會被包裝在AggregateException
中,您必須相應地處理這些異常。
可以找到一個很好的解釋on MSDN here。在進入async
/await
之前,我會推薦學習C#4.0任務,因爲它會讓您更好地理解併發性。
我的理解正確的文章,問題是,如果我使用Tas.Run,我創建一個新的線程,並且這使用更多的資源,所以目標是不使用異步方法的新線程。問題是,到目前爲止,我不知道如何在沒有任務的情況下實現異步方法。運行而不是阻止用戶界面。本文使用TaskCompletionSource,它不創建一個新線程,但我不知道如何以正確的方式使用它。 –
請參閱編輯一些更多的說明。 – MoonKnight
聽起來像是你誤解了運行「異步」的概念,因爲它基本上總是涉及第二個線程。如果你不習慣創建/刪除額外的線程,你可以創建一個額外的線程,等待事情處理(不忙循環!),基本上重用它的資源。缺點是,每次運行只能處理一個異步請求,但它會起作用。 – Mario
但是如果我使用task.Run創建一個新線程,並且如果我沒有錯,這將創建一個新線程,這是我們想要避免的原因,因爲使用更多資源並且可擴展性更差。是否有可能在不創建新線程的情況下在任務中執行代碼? –
代碼將在哪裏運行? –
是的。然後,如果我使用像killercam這樣的代碼,那就是我是doinf,它與在任務中包裝同步方法以創建異步方法的方法相同。如果這是真的,在我的文章中,作者說這不是一個好習慣。 –