2013-03-12 28 views
12

Tôi đã cố gắng sử dụng phương thức SwitchTo ngày hôm nay để chuyển sang chủ đề GUI và thấy rằng ví dụ tôi gỡ bỏ nó không hoạt động, đơn giản vì phương thức này không có.Tại sao "SwitchTo" bị xóa khỏi Async CTP/Release?

Sau đó tôi tìm thấy lời giới thiệu này here:

Lý do chúng tôi đã thoát khỏi nó là vì nó rất nguy hiểm. Cách khác là kết hợp mã của bạn bên trong TaskEx.Run ...

Câu hỏi của tôi đơn giản là: Tại sao có nguy hiểm không? Những nguy hiểm cụ thể sẽ sử dụng nó dẫn đến?

Lưu ý rằng tôi đã làm đọc phần còn lại của bài đăng đó, vì vậy tôi hiểu rằng có những giới hạn kỹ thuật ở đây. Câu hỏi của tôi vẫn là, nếu tôi biết điều này, tại sao lại là nguy hiểm?

Tôi đang xem xét việc thực hiện lại các phương thức trợ giúp để cung cấp cho tôi chức năng được chỉ định, nhưng nếu có điều gì đó bị hỏng, ngoài việc ai đó đã quyết định là nguy hiểm, tôi sẽ không làm điều đó.

Cụ thể, rất ngây thơ, dưới đây là cách tôi sẽ xem xét việc thực hiện các phương pháp cần thiết:

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() 
    { 
    } 
} 

Điều này sẽ cho phép tôi viết mã như thế này:

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

Hah.Bây giờ đó là một chủ đề cũ! Tôi không bao giờ là một fan hâm mộ của Microsoft thỉnh thoảng "đó là vì lý do của chính bạn". –

+1

Tôi đã chuyển sang làm 'chờ đợi Task.Run (async() => {}) '- không để tránh một số mối nguy hiểm trống rỗng, nhưng đơn giản bởi vì tôi nghĩ rằng nó dễ đọc hơn. Tôi nghĩ rằng ý tưởng của bạn về cách thực hiện 'SwitchTo()' là âm thanh, mặc dù. –

+0

Không biết về cú pháp 'async() => {} ', cần điều tra thêm, cảm ơn! –

Trả lời

6

Stephen Toub có một số chi tiết thông tin về lý do trong this thread.

Để tóm tắt, nó không phải là một ý tưởng tốt vì hai lý do:

  1. Nó thúc đẩy đang không có cấu trúc. Nếu bạn có "xử lý nặng" mà bạn cần phải làm, nó sẽ được đặt trong một Task.Run. Thậm chí tốt hơn, tách logic nghiệp vụ của bạn khỏi logic UI của bạn.
  2. Xử lý lỗi và (một số) lần tiếp tục chạy trong ngữ cảnh không xác định. Các khối catch/finally trong Test sẽ cần xử lý chạy trong ngữ cảnh giao diện người dùng hoặc Giao diện người dùng (và nếu chúng chạy trong ngữ cảnh nhóm luồng, họ không thể sử dụng SwitchTo để nhảy trên ngữ cảnh giao diện người dùng). Ngoài ra, miễn là bạn await trả lại Task bạn phải OK (await sẽ sửa ngữ cảnh tiếp tục nếu cần), nhưng nếu bạn có các liên kết rõ ràng sử dụng ExecuteSynchronously, thì chúng sẽ có cùng vấn đề với khối catch/finally .

Tóm lại, mã này sạch hơn và dễ dự đoán hơn mà không cần SwitchTo.

+0

Ok, điều đó làm sáng tỏ thêm về nó. Nó vẫn trông kỳ quặc, bài viết đó, để nói nó tạo ra tất cả các loại vấn đề với các ngữ cảnh không xác định, và sau đó chuyển sang để hiển thị cách thực hiện hỗ trợ. –

+0

@ LasseV.Karlsen Tôi nghĩ rằng thái độ đó không phải là không phổ biến đối với các nhà phát triển của .Net. Khi tôi hiểu nó, họ đang nói một cái gì đó như “Nếu chúng tôi cung cấp tính năng này, mọi người sẽ nghĩ rằng nó là okay để sử dụng nó, vì vậy họ sẽ sử dụng nó thường xuyên, đó là một điều xấu. Nhưng nếu nó được đăng trên một số blog, họ có thể sử dụng nó chỉ khi họ thực sự cần nó và hiểu những gì đang xảy ra, đó là okay. ” – svick

+0

@svick Tôi có thể chấp nhận điều đó :) –

2

ConfigureAwait thực sự nguy hiểm hơn SwitchTo. Theo dõi tinh thần ngữ cảnh hiện tại và cuộc gọi SwitchTo cuối cùng không khó khăn hơn việc theo dõi nơi một biến được gán lần cuối. Mặt khác, ConfigureAwait chuyển ngữ cảnh nếu và chỉ khi cuộc gọi thực sự chạy không đồng bộ. Nếu tác vụ đã được hoàn thành, ngữ cảnh được giữ nguyên. Bạn không kiểm soát được điều này.

Các vấn đề liên quan