C# 为什么新线程可以访问UI?
以以下方法为例:C# 为什么新线程可以访问UI?,c#,windows-runtime,windows-store-apps,async-await,C#,Windows Runtime,Windows Store Apps,Async Await,以以下方法为例: private async void F() { button.IsEnabled = false; await Task.Delay(1000); button.IsEnabled = true; } 在这种情况下,任何以await开头的代码总是出现在另一个线程(编辑:错误)上,该线程可能无法访问UI线程,类似于桌面应用程序。在类似情况下,我记得有一个例外,例如: 应用程序调用了为不同线程封送的接口 但是,该示例不会触发任何异常。这是预期的吗?我能可
private async void F()
{
button.IsEnabled = false;
await Task.Delay(1000);
button.IsEnabled = true;
}
在这种情况下,任何以await
开头的代码总是出现在另一个线程(编辑:错误)上,该线程可能无法访问UI线程,类似于桌面应用程序。在类似情况下,我记得有一个例外,例如:
应用程序调用了为不同线程封送的接口
但是,该示例不会触发任何异常。这是预期的吗?我能可靠地编写这样的代码吗?在UI线程上运行的代码具有
同步上下文。您可以通过打印SynchronizationContext.Current
看到这一点。在等待某个内容之前,捕获该上下文;在等待之后,代码在该上下文上恢复,从而确保继续在UI线程上运行
要获取所引用的行为,如果继续在ThreadPool
线程上运行,则可以使用ConfigureAwait(false)
禁用SynchronizationContext
捕获:
此代码将引发您期望的异常
这是预期的吗?我能可靠地编写这样的代码吗
是的,是的。默认情况下,使用async await的代码将“做正确的事情”。但是,如果您确实希望将某些内容卸载到线程池
线程中,则可以使用任务。运行
任何从wait开始的代码总是出现在另一个线程上(非UI线程,对吗?)
不,一点也不<代码>等待
不会启动其他线程。如果你觉得这句话令人困惑,我有一个可能会有所帮助的建议
wait
将要做的是将方法的剩余部分安排为在异步操作完成后继续运行(在这种情况下,异步操作只是一个计时器触发)。默认情况下,wait
将捕获一个“上下文”,它是SynchronizationContext.Current
(或者,如果它是null
,则上下文是TaskScheduler.Current
)。在这种情况下,有一个UISynchronizationContext
,它确保async
方法的其余部分将在UI线程上运行。我想我错了,wait
之外的代码在不同的线程上运行,因此它被发布到SynchronizationContext
,由UI线程使用?@Avenicci任务后的继续。延迟完成被发布到SC,以确保它在UI线程上运行。可以肯定的是,Task.Delay
是否启动新线程?我记得有人这样争论的一条线索。@Avenicci:没有。它只是启动了一个计时器。上次我检查时,每个应用程序都有一个线程,可以同时处理所有计时器。当计时器完成时,它的回调在线程池线程上被调用,线程池线程只用于完成从Task.Delay
返回的Task
。但是没有创建新线程。如果Task.Delay
使用相同的线程,异步方法如何直接终止?@Avenicci:调用线程不终止-它只是返回。
private async void FooAsync()
{
button.IsEnabled = false;
await Task.Delay(1000).ConfigureAwait(false);
button.IsEnabled = true;
}