2013-03-12 48 views
12

我今天嘗試使用SwitchTo方法切換到GUI線程,發現我解除它的例子不起作用,只是因爲方法不存在。爲什麼將「SwitchTo」從Async CTP/Release中刪除?

然後我發現這個Blurb的here

我們擺脫它的原因是因爲它是如此的危險。另一種方法是捆紮內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 
} 
+0

哈。現在這是一個相當古老的線程!我從來沒有成爲微軟偶爾的「這是爲了你自己的好」推理的粉絲。 – 2013-03-12 14:37:01

+1

我已經切換到'等待Task.Run(async()=> {})' - 不是爲了避免一些空洞的危險,而僅僅是因爲我認爲它更容易閱讀。不過,我認爲你的想法是如何實現'SwitchTo()'。 – 2013-03-12 14:37:52

+0

不知道'async()=> {}'語法,需要進一步調查,謝謝! – 2013-03-12 14:46:24

回答

6

斯蒂芬Toub有一些更多的信息推理在this thread

總之,它不是有兩個原因一個好主意:

  1. 它促進非結構化代碼。如果您需要執行「重處理」,則應將其置於Task.Run。更好的是,將您的業務邏輯與UI邏輯分開。
  2. 錯誤處理和(一些)延續運行在未知的上下文中。 catch/finallyTest中的塊需要處理線程池中的運行 UI上下文(如果它們在線程池上下文中運行,則它們不能使用SwitchTo跳轉到UI上下文中)。另外,只要你await返回Task你應該確定(await將根據需要糾正連續上下文),但如果你有明確的ContinueWith延續使用ExecuteSynchronously,那麼他們就會有相同的問題,因爲catch/finally塊。

簡而言之,如果沒有SwitchTo,則代碼更清晰且更具可預測性。

+0

好的,這讓我們更清楚了。這篇文章看起來仍然很奇怪,說它會帶來各種未知情況下的問題,然後繼續展示如何實施支持。 – 2013-03-12 15:06:37

+0

@ LasseV.Karlsen我認爲這種態度對於.Net開發者來說並不罕見。據我瞭解,他們說的是「如果我們提供了這個功能,人們會認爲它可以使用它,所以他們會經常使用它,這是一件壞事。但是如果它發佈在某個博客上,他們很可能只在他們真正需要它時才使用它,並且瞭解到底發生了什麼,這沒關係。「 – svick 2013-03-13 00:37:32

+0

@svick我可以接受:) – 2013-03-13 20:04:11

2

ConfigureAwait實際上比SwitchTo更危險。精神跟蹤當前上下文和最後一次SwitchTo調用並不比追蹤變量上次分配的位置更困難。另一方面,當且僅當調用實際上異步運行時,ConfigureAwait切換上下文。如果任務已完成,則會保留上下文。你無法控制這一點。

相關問題