讓我們打破這裏發生了什麼
當您control_SelectionValueChanged
處理程序便會啓動,我認爲我們在UI線程上運行,則然後:。
- 揭開序幕
SomeMethodAsync
上線池線程通過Task.Run
。這不會阻止UI線程。
- 一旦線程池線程開始執行
SomeMethodAsync
您正在要求運行時通過調用Control.Invoke
將您的返回回傳給UI線程。雖然SomeMethodA
正在UI線程上執行,但同時也會阻塞線程池線程。
- 然後,您解除對線程池線程的阻塞並要求它執行一些其他的
async
方法。整個操作將保持關閉UI
線程(除非裏面有SomeOtherMethodAsync
東西時髦,即另一個Control.Invoke
呼叫)
- 後
await
返回到一個線程池線程 - 這可能是同一個線程池中的線程作爲前await
,或不同的 - 這是由TaskScheduler
。
- 如果
variable
是true
,則在UI線程上執行SomeMethodB
(同時再次阻塞線程池線程)。
- 最後,您在UI線程上執行
SomeMethodC
(同時最後一次阻塞線程池線程)。
正如你所看到的,大部分時間SomeMethodAsync
正在執行(與花等待SomeOtherMethodAsync
的時間以外,與Control.Invoke
調用之間短暫的時間),你仍然在使用UI線程,但你也阻塞你的線程池線程。所以你現在正在佔用兩條線程,其中大多數只有其中一個線程正在做有用的工作 - 另一線程只是坐在那裏等待。
除了非常可怕的閱讀,這是非常低效。
考慮以下改寫:
private async void control_SelectionValueChanged(Object sender, EventArgs e)
{
try
{
await SomeMethodAsync();
}
catch (Exception ex)
{
// We're an async void, so don't forget to handle exceptions.
MessageBox.Show(ex.Message);
}
}
private async Task SomeMethodAsync()
{
// We're on the UI thread, and we will stay on the UI
// thread *at least* until we hit the `await` keyword.
SomeMethodA();
// We're still on the UI thread, but if `SomeOtherMethodAsync`
// is a genuinely asynchronous method, we will go asynchronous
// as soon as `SomeOtherMethodAsync` hits the its `await` on a
// `Task` that does not transition to `Completed` state immediately.
bool variable = await SomeOtherMethodAsync();
// If you need stronger guarantees that `SomeOtherMethodAsync`
// will stay off the UI thread, you can wrap it in Task.Run, so
// that its synchronous portions (if any) run on a thread pool
// thread (as opposed to the UI thread).
// bool variable = await Task.Run(() => SomeOtherMethodAsync());
// We're back on the UI thread for the remainder of this method.
if (variable) SomeMethodB();
// Still on the UI thread.
SomeMethodC();
}
以上是在行爲方面相似(雖然不是完全等同),不過,是不是更容易閱讀?
難道'任務task = SomeMethodAsync()'你非異步方法更有意義。MethodInvoker代碼的邏輯是什麼? – Magnus
爲什麼它會更有意義? Invoke調用的方法是屬於UI線程的同步方法。 SomeOtherMethodAsync是api調用(異步)。 –
這條線對我來說毫無意義。您創建一個任務只是爲了等待另一個任務。爲什麼不直接返回第一個任務(SomeMethodAsync的結果)。 – Magnus