为什么“SWITCHTO”从异步CTP /版本中删除?(Why was “SwitchTo” rem

2019-07-21 10:05发布

我试图用SWITCHTO方法今天切换到GUI线程,并发现我举起它的例子不工作,仅仅是因为该方法是不存在的。

然后我发现这个Blurb的在这里 :

我们摆脱它的原因是因为它是如此的危险。 另一种方法是捆扎内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()
    {
    }
}

这将让我写这样的代码:

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
}

Answer 1:

斯蒂芬Toub对在推理的一些详细信息, 这个线程 。

总之,这不是有两个原因一个好主意:

  1. 它促进非结构化代码。 如果你有“重处理”,你需要做的,它应该被放置在一个Task.Run 。 更妙的是,从你的UI逻辑中分离出来的业务逻辑。
  2. 错误处理和(部分)延续在一个未知的环境中运行。 catch / finallyTest将需要处理的线程池 UI上下文中运行(如果他们是在线程池上下文中运行,他们不能使用SwitchTo跳上UI上下文)。 另外,只要你await返回的Task ,你应该确定( await将根据需要纠正连续上下文),但如果你有明确的ContinueWith使用延续ExecuteSynchronously ,那么他们就会有相同的问题,因为catch / finally块。

总之,代码更清洁,更可预测的不SwitchTo



Answer 2:

ConfigureAwait实际上比SWITCHTO更危险。 精神上跟踪当前上下文和最后SWITCHTO通话不超过跟踪其中一个变量的最后分配更加困难。 在另一方面,ConfigureAwait上下文切换,当且仅当调用实际上异步运行。 如果任务已经完成,上下文将被保留。 你必须在这个没有控制权。



文章来源: Why was “SwitchTo” removed from Async CTP / Release?