让我们打破这里发生了什么
当您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