我正在研究一個可擴展的遊戲服務器系統,並試圖對這個新項目過度使用await/async。直到現在,我還是遇到了幾個陷阱。我已經找出了大部分解決方案,並開發了一種「常見做法」,即如何編寫異步方法,以便避免這些缺陷易於檢測。不幸的是,下面讓我頭疼:檢測異步/等待濫用:阻止阻止呼叫
1)例:
async Task<int> RunSqlQuery()
{
DbCommand cmd = conn.CreateCommand();
...
cmd.ExecuteReader();
...
}
WHOOOM!由於以下幾個原因,這是一個混蛋。一,有一個ExecuteReaderAsync(),它可以解決問題。其次,這個調用將阻止和阻止內部異步框架的工作線程。在桌面環境中不是太關鍵,但不幸的是,如果您的服務器每秒處理8000個請求,這可能會嚴重損害您的性能,並且追蹤導致問題的確切線條可能非常困難。
2)例:
void ThisHurts()
{
someTask.GetAwaiter().GetResult();
}
async Task<int> RunQuery()
{
...
lock(something)
{
ThisHurts();
}
...
}
我承認這個看起來有點設計,以證明我的觀點,但有大量的代碼打交道時,這是一個情況是很難避免的。基本上調用等待鎖是致命的。它是一個等待發生的災難(字面上)。有很多解釋爲什麼,相信與否,他們是真實的,建立像上面的東西,你的代碼將幾乎立即死亡,如果你有你的服務器上的負載和噸的競爭條件開始鏈接在一起...
所以這個問題是關於如何檢測await的那些錯誤用法。有沒有像Resharper這樣的工具(它似乎不支持我想要的大部分)。我認爲微軟應該標記所有非阻塞方法,並強制人們以異步方式包裝它們,或者在嘗試在異步方法中調用它們時發出編譯器錯誤。此外,他們可能會迫使你使用一個新的「塊」 - 關鍵字被添加到所有未標記爲非阻塞的方法前面,以便您可以使用它們,但立即顯示羞恥。
到目前爲止我看到的與異步框架有關的主要問題是,濫用只會在重負載下顯示,這通常非常難以調試跟蹤,因爲它擁有如此多的數據以及附加debuger的問題是走了,因爲負荷消失了。真棒;)
'標記的所有無阻塞的方法和力量的人要麼將它們包裝在異步兼容的方式'這是不可能的。如果你有一個阻塞方法,使其異步的唯一方法是完全重寫它以使用非阻塞IO。 – SLaks
這曾經被稱爲「設計錯誤」,之前沒有聽說過它叫做「災難」。我想,如果你在項目結束時做TDD的話。 –
「追蹤導致問題的確切線條非常困難。」我不這麼認爲。Profiler可以告訴你你的代碼在哪裏花了很多時間。如果你阻止了很多,你會在那裏看到那個方法。 – svick