我如何知道异步方法调用是否更改了调用者的上下文?
How do I know if an async method call changes the caller's context?
考虑这个例子:
async Task Foo()
{
button.Text = "This is the UI context!";
await BarA();
button.Text = "This is still the UI context!";
await BarB();
button.Text = "Oh no!"; // exception (?)
}
async Task BarA()
{
await Calculations();
}
async Task BarB()
{
await Calculations().ConfigureAwait(false);
}
我如何知道调用 await BarB()
是否更改了上下文 而无需 读取 async Task BarB()
函数的主体?我真的需要确切地知道异步函数是否在任何时候调用 ConfigureAwait(false)
吗?又或者例子是错误的,没有例外?
BarB()
做什么在很大程度上是无关紧要的,除非 BarB()
需要与 UI 交谈。这里的重要部分是行中的 await
:
await BarB();
await
也捕获上下文 - 并协商将 返回 到正确的上下文,如果它发现自己从 错误的 上下文继续。所以;除非你写:
await BarB().ConfigureAwait(false);
你在这里应该没问题。
BarB()
中的ConfigureAwait(false)
看起来很正常,可能是正确的,如果我们假设BarB()
不需要直接更新UI 或执行任何其他上下文绑定操作。
补充 - 请记住 async
是方法的 实现细节 。一个方法如何或为什么创建它返回给你的 Task
在很大程度上是透明的(这就是为什么 async
不是签名的一部分,在接口定义等中不允许)
虽然您的方法确实与其调用的方法共享 "current context",但这只是在这些方法(如果它们想知道当前上下文)将调用 SynchronizationContext.Current
的范围内。然后,如果需要,他们将使用方法 on 该上下文来获取 "back on it"。对上下文的任何 "changes" 通常实际上是通过 将延续切换到已经设置了正确上下文的合适线程来执行的 .
这些方法通常不会调用SetSynchronizationContext
。只有当一个方法确实调用它时,您才需要担心 "your" 上下文的更改。 (如果它们的同步上下文是自由线程但需要其他环境资源,一些基础结构代码可能会调用该方法。它们将获得一个线程池线程,调用 SetSynchronizationContext
,执行延续,然后再次取消设置同步上下文)。
考虑这个例子:
async Task Foo()
{
button.Text = "This is the UI context!";
await BarA();
button.Text = "This is still the UI context!";
await BarB();
button.Text = "Oh no!"; // exception (?)
}
async Task BarA()
{
await Calculations();
}
async Task BarB()
{
await Calculations().ConfigureAwait(false);
}
我如何知道调用 await BarB()
是否更改了上下文 而无需 读取 async Task BarB()
函数的主体?我真的需要确切地知道异步函数是否在任何时候调用 ConfigureAwait(false)
吗?又或者例子是错误的,没有例外?
BarB()
做什么在很大程度上是无关紧要的,除非 BarB()
需要与 UI 交谈。这里的重要部分是行中的 await
:
await BarB();
await
也捕获上下文 - 并协商将 返回 到正确的上下文,如果它发现自己从 错误的 上下文继续。所以;除非你写:
await BarB().ConfigureAwait(false);
你在这里应该没问题。
BarB()
中的ConfigureAwait(false)
看起来很正常,可能是正确的,如果我们假设BarB()
不需要直接更新UI 或执行任何其他上下文绑定操作。
补充 async
是方法的 实现细节 。一个方法如何或为什么创建它返回给你的 Task
在很大程度上是透明的(这就是为什么 async
不是签名的一部分,在接口定义等中不允许)
虽然您的方法确实与其调用的方法共享 "current context",但这只是在这些方法(如果它们想知道当前上下文)将调用 SynchronizationContext.Current
的范围内。然后,如果需要,他们将使用方法 on 该上下文来获取 "back on it"。对上下文的任何 "changes" 通常实际上是通过 将延续切换到已经设置了正确上下文的合适线程来执行的 .
这些方法通常不会调用SetSynchronizationContext
。只有当一个方法确实调用它时,您才需要担心 "your" 上下文的更改。 (如果它们的同步上下文是自由线程但需要其他环境资源,一些基础结构代码可能会调用该方法。它们将获得一个线程池线程,调用 SetSynchronizationContext
,执行延续,然后再次取消设置同步上下文)。