ang*_*son 13 c# asynchronous async-await async-ctp
我今天尝试使用SwitchTo方法切换到GUI线程,并发现我解除它的示例不起作用,仅仅是因为该方法不存在.
然后我在这里发现了这个模糊:
我们摆脱它的原因是因为它太危险了.另一种方法是在TaskEx.Run中捆绑你的代码......
我的问题很简单:为什么它很危险?使用它会带来哪些特定的危险?
请注意,我确实阅读了该帖子的其余部分,因此我确实理解这里存在技术限制.我的问题仍然是,如果我意识到这一点,为什么它很危险?
我正在考虑重新实现帮助方法来给我指定的功能,但如果有一些根本性的破坏,除了有人认为它是危险的,我不会这样做.
具体来说,非常天真,这是我如何考虑实现所需的方法:
public static class ContextSwitcher
{
public static ThreadPoolContextSwitcher SwitchToThreadPool()
{
return new ThreadPoolContextSwitcher();
}
public static SynchronizationContextSwitcher SwitchTo(this SynchronizationContext synchronizationContext)
{
return new SynchronizationContextSwitcher(synchronizationContext);
}
}
public class SynchronizationContextSwitcher : INotifyCompletion
{
private readonly SynchronizationContext _SynchronizationContext;
public SynchronizationContextSwitcher(SynchronizationContext synchronizationContext)
{
_SynchronizationContext = synchronizationContext;
}
public SynchronizationContextSwitcher GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get
{
return false;
}
}
public void OnCompleted(Action action)
{
_SynchronizationContext.Post(_ => action(), null);
}
public void GetResult()
{
}
}
public class ThreadPoolContextSwitcher : INotifyCompletion
{
public ThreadPoolContextSwitcher GetAwaiter()
{
return this;
}
public bool IsCompleted
{
get
{
return false;
}
}
public void OnCompleted(Action action)
{
ThreadPool.QueueUserWorkItem(_ => action(), null);
}
public void GetResult()
{
}
}
Run Code Online (Sandbox Code Playgroud)
这将允许我编写这样的代码:
public async void Test()
{
await ContextSwitcher.SwitchToThreadPool(); // ensure we're not bogging down the UI thread
// do some heavy processing
await _UIContext.SwitchTo(); // presumably saved from the main thread
// update UI with new data
}
Run Code Online (Sandbox Code Playgroud)
Stephen Toub在这个帖子中有更多关于推理的信息.
总而言之,出于两个原因,这不是一个好主意:
Task.Run.更好的是,将业务逻辑与UI逻辑分开.catch/ finallyblocks in Test需要处理在线程池或 UI上下文中运行(如果它们在线程池上下文中运行,则它们不能用于SwitchTo跳转UI上下文).此外,只要您await返回,Task您应该没问题(await如果需要,将更正连续上下文),但如果您有明确的ContinueWith继续使用ExecuteSynchronously,那么它们将具有与catch/ finallyblocks 相同的问题.简而言之,代码更清晰,更具可预测性SwitchTo.
ConfigureAwait 实际上比 SwitchTo 更危险。心理上跟踪当前上下文和最后一次 SwitchTo 调用并不比跟踪变量上次分配的位置更困难。另一方面,当且仅当调用实际异步运行时,ConfigureAwait 才会切换上下文。如果任务已经完成,则保留上下文。你无法控制这一点。