为什么新线程可以访问UI?
Why can new threads access the UI?
以下面的方法为例:
private async void F()
{
button.IsEnabled = false;
await Task.Delay(1000);
button.IsEnabled = true;
}
在这种情况下,任何从 await
开始的代码总是出现在另一个线程上(编辑:错误),这可能不应该访问 UI 线程,类似于桌面应用程序。在类似的情况下,我记得有一个例外,例如:
The application called an interface that was marshalled for a different thread.
但是,该示例没有触发任何异常。这是预期的吗?我能可靠地编写这样的代码吗?
UI 线程上的代码 运行ning 有一个 SynchronizationContext
。您可以通过打印 SynchronizationContext.Current
看到这一点。在你等待上下文被捕获之前,等待你的代码在那个上下文上恢复,这确保 UI 线程上的延续 运行s。
要获得您正在引用的行为,其中延续是 ThreadPool
线程上的 运行,您可以使用 ConfigureAwait(false)
禁用 SynchronizationContext
捕获:
private async void FooAsync()
{
button.IsEnabled = false;
await Task.Delay(1000).ConfigureAwait(false);
button.IsEnabled = true;
}
此代码将引发您预期的异常。
Is this expected? Can I reliably write code like this?
是的,是的。默认情况下,使用 async-await 的代码将 "do the right thing"。但是如果你确实想将某些东西卸载到 ThreadPool
线程,你可以使用 Task.Run
.
any code starting at await always occurs on another thread (non-UI thread, right?),
不,一点也不。 await
不启动其他线程。我有一个 async
intro 如果你觉得这个陈述令人困惑,它可能会有所帮助。
await
将做的是将方法的其余部分安排为异步操作完成后运行的延续(在这种情况下,异步操作只是一个定时器触发)。默认情况下,await
将捕获一个 "context",即 SynchronizationContext.Current
(或者,如果是 null
,则上下文是 TaskScheduler.Current
)。在这种情况下,有一个 UI SynchronizationContext
确保 async
方法的其余部分将 运行 在 UI 线程上。
以下面的方法为例:
private async void F()
{
button.IsEnabled = false;
await Task.Delay(1000);
button.IsEnabled = true;
}
在这种情况下,任何从 await
开始的代码总是出现在另一个线程上(编辑:错误),这可能不应该访问 UI 线程,类似于桌面应用程序。在类似的情况下,我记得有一个例外,例如:
The application called an interface that was marshalled for a different thread.
但是,该示例没有触发任何异常。这是预期的吗?我能可靠地编写这样的代码吗?
UI 线程上的代码 运行ning 有一个 SynchronizationContext
。您可以通过打印 SynchronizationContext.Current
看到这一点。在你等待上下文被捕获之前,等待你的代码在那个上下文上恢复,这确保 UI 线程上的延续 运行s。
要获得您正在引用的行为,其中延续是 ThreadPool
线程上的 运行,您可以使用 ConfigureAwait(false)
禁用 SynchronizationContext
捕获:
private async void FooAsync()
{
button.IsEnabled = false;
await Task.Delay(1000).ConfigureAwait(false);
button.IsEnabled = true;
}
此代码将引发您预期的异常。
Is this expected? Can I reliably write code like this?
是的,是的。默认情况下,使用 async-await 的代码将 "do the right thing"。但是如果你确实想将某些东西卸载到 ThreadPool
线程,你可以使用 Task.Run
.
any code starting at await always occurs on another thread (non-UI thread, right?),
不,一点也不。 await
不启动其他线程。我有一个 async
intro 如果你觉得这个陈述令人困惑,它可能会有所帮助。
await
将做的是将方法的其余部分安排为异步操作完成后运行的延续(在这种情况下,异步操作只是一个定时器触发)。默认情况下,await
将捕获一个 "context",即 SynchronizationContext.Current
(或者,如果是 null
,则上下文是 TaskScheduler.Current
)。在这种情况下,有一个 UI SynchronizationContext
确保 async
方法的其余部分将 运行 在 UI 线程上。