我正在嘗試檢查布林值是否為真,如果為假,請繼續檢查直到它為真。我發現了這一點,但我并不真正理解這個例子。我什么也沒找到,我試著很容易地做到這一點,但它不起作用,它很冷。
private void dashboard_Paint(object sender, PaintEventArgs e)
{
if (IsLogged().GetAwaiter().GetResult())
{
Console.WriteLine("Logged");
}
}
public async Task<Boolean> IsLogged()
{
while (!logged)
{
if (logged)
return true;
await Task.Delay(25);
}
return false;
}
uj5u.com熱心網友回復:
TaskC# 中的 s 是一種實作協作式多任務處理的方法,其中許多任務可能會在同一個執行緒上運行,每個任務都做少量作業,然后再讓出 cpu 以供其他任務執行。如果其中一項任務行為不端并且沒有回傳給任務調度程式,則執行緒被阻塞并且在塊被清除之前不會運行任何任務。當再次呼叫任務時,它會從中斷的地方繼續。
默認任務調度程式在執行緒池上運行任務,這有??助于減輕(但不是消除)執行緒阻塞的影響。在 WinForms 上,雖然任務調度程式默認設定為在 UI 執行緒上運行任務,因為很多操作只能從主執行緒完成。總的來說,這是一件好事,但只要出現執行緒阻塞,就會出現問題。您不是阻塞一組執行緒池執行緒中的一個,而是阻塞您的 UI 和所有其他執行緒正在運行的執行緒。
處理這個問題的方法是在任何有意義的地方async使用。await如果您一直在等待任務完成,請使用await它來完成。如果您發現自己在使用.Result,.Wait()或者.GetAwaiter().GetResult()然后問自己是否可以將其重寫為async方法,即使您必須使用async void事件處理程式也是如此。
對于您的繪畫事件,這意味著這樣做:
private async void dashboard_Paint(object sender, PaintEventArgs e)
{
if (await IsLogged())
Console.WriteLine("Logged");
}
(雖然您通常不應該使用async void,但這是異步事件處理程式的要求,因為事件簽名delegate void X(...)不是delegate Task X(...).)
我不會討論為什么您永遠不應該在OnPaint事件處理程式中等待,或者為什么您的IsLogged示例有問題(并且可能應該被呼叫WaitLogged),但是您可能需要注意一件事以防萬一:volatile關鍵詞。
假設這logged是一個欄位而不是屬性,優化器可以捕獲該欄位的值并在方法的生命周期內繼續使用該捕獲的值。關鍵字告訴優化器這volatile不應該發生,并且每次參考都logged應該總是導致從變數而不是捕獲的值中讀取。
在最壞的情況下,您最終可能會得到如下所示的優化代碼:
private async Task<bool> IsLogged()
{
if (!logged)
{
while (true)
await Task.Delay(25)
}
return true;
}
從優化器的角度來看,這就是您的代碼所做的。它不知道該logged值可以被其他東西改變,所以它不考慮那個選項。添加volatile讓它知道它不能這樣做。
uj5u.com熱心網友回復:
private async Task dashboard_Paint(object sender, PaintEventArgs e)
{
if (await IsLogged())
{
Console.WriteLine("Logged");
}
}
這應該可以解決凍結問題,因為如果使用不當,GetAwaiter() 有時會凍結。
您是否嘗試檢查將日志記錄布林值設定為 true 的原因?這似乎是一個無限回圈。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/489800.html
