2012-02-17 15 views
7

Tôi đang cố gắng hiểu khi nào nên sử dụng TaskEx.Run. Tôi đã cung cấp hai mẫu mã tôi đã viết dưới đây mà sản xuất cùng một kết quả. Những gì tôi không thấy là lý do tại sao tôi sẽ lấy Task.RunExTaskEx.RunEx cách tiếp cận , tôi chắc chắn có một lý do chính đáng và đã hy vọng ai đó có thể điền vào tôi trong.Khi nào sử dụng TaskEx.Run và TaskEx.RunEx

async Task DoWork(CancellationToken cancelToken, IProgress<string> progress) 
{ 
    int i = 0; 
    TaskEx.RunEx(async() => 
     { 
      while (!cancelToken.IsCancellationRequested) 
      { 
       progress.Report(i++.ToString()); 
       await TaskEx.Delay(1, cancelToken); 
      } 
     }, cancelToken); 
} 
private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    if (button.Content.ToString() == "Start") 
    { 
     button.Content = "Stop"; 
     cts.Dispose(); 
     cts = new CancellationTokenSource(); 
     listBox.Items.Clear(); 
     IProgress<string> progress = new Progress<string>(s => 
     { 
      listBox.Items.Add(s); 
      listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); 
     }); 
     DoWork(cts.Token, progress); 
    } 
    else 
    { 
     button.Content = "Start"; 
     cts.Cancel(); 
    } 
} 

tôi có thể đạt được kết quả tương tự giống như vậy

async Task DoWork(CancellationToken cancelToken) 
    { 
     int i = 0; 
     while (!cancelToken.IsCancellationRequested) 
     { 
      listBox.Items.Add(i++); 
      listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); 
      await TaskEx.Delay(100, cancelToken); 

     } 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     if (button.Content.ToString() == "Start") 
     { 
      button.Content = "Stop"; 
      cts.Dispose(); 
      cts = new CancellationTokenSource(); 
      listBox.Items.Clear(); 
      DoWork(cts.Token); 
     } 
     else 
     { 
      button.Content = "Start"; 
      cts.Cancel(); 
     } 
    } 
+0

Chủ đề trên là thảo luận về lý do TaskEx.RunEx, tất cả đều liên quan đến những thay đổi không thể đưa vào chức năng .NET cốt lõi cho CTP, nhưng sẽ được tích hợp đúng cách để phát hành cuối cùng –

+0

Đã thay đổi 'Tác vụ .RunEx' đến 'TaskEx.RunEx' Không có' Run() 'cũng không phải' RunEx() 'trong lớp Async CTP' Task'. Cả hai đều trong 'TaskEx'. Đúng, nếu tôi sai –

Trả lời

0

Task.Run sinh ra một chuỗi mới trong hầu hết các trường hợp như tôi đã hiểu. Điều quan trọng cần lưu ý là đơn giản vì bạn đánh dấu một phương thức là không đồng bộ, và sử dụng awaiters, điều này KHÔNG (nhất thiết) có nghĩa là các luồng mới đang được tạo, các lần hoàn thành được lên lịch trên chuỗi thực thi SAME mà chúng được gọi từ trong nhiều trường hợp.

Bí quyết ở đây phải làm với SchedulingContext. Nếu nó được thiết lập cho một căn hộ đa luồng, sau đó bạn sẽ đại biểu hoàn thành các chủ đề khả thi trên threadpool. Nếu bạn đang ở trong một căn hộ đơn giản như tất cả các mã WPF và WinForms UI, thì nó sẽ trở về chuỗi gọi để hoàn thành cho phép công việc được thực hiện trực tiếp trên giao diện người dùng mà không nhìn thấy chủ đề marshalling trong mã.

+0

'Hàng đợi Task.Run' vào nhóm luồng, thường không bắt đầu một chuỗi mới. 'await' sắp xếp các tiếp tục của nó thành' SynchronizationContext' hoặc 'TaskScheduler' hiện tại của nó (không phải luồng) - xem phần cuối của [bài viết này] (http://msdn.microsoft.com/en-us/magazine/gg598924.aspx) mà vẫn áp dụng như của CTP v3 (và xem trước dev VS11). Tôi cũng bao gồm bối cảnh async trong [bài đăng giới thiệu không đồng bộ của tôi] (http://nitoprograms.blogspot.com/2012/02/async-and-await.html).Ngữ cảnh này không liên quan gì đến MTA hoặc STA, mặc dù có thể có ngữ cảnh hỗ trợ STA hoặc MTA. –

+0

Tôi đã chỉnh sửa dễ dàng: D – Firoso

11

Sử dụng TaskEx.Run khi bạn muốn chạy mã đồng bộ trong ngữ cảnh nhóm luồng.

Sử dụng TaskEx.RunEx khi bạn muốn chạy mã không đồng bộ trong ngữ cảnh nhóm luồng.

Stephen Toub có hai bài đăng trên blog liên quan đến sự khác biệt trong hành vi:

Đây chỉ là một trong nhiều lựa chọn bạn có cho creating tasks. Nếu bạn không phải sử dụng Run/RunEx, thì bạn không nên sử dụng. Sử dụng các phương thức async đơn giản và chỉ sử dụng Run/RunEx nếu bạn cần chạy một thứ gì đó ở chế độ nền.

+0

Thực ra điều đó không đúng ... RunEx phải làm với các biểu thức lambda trả về giá trị ... không phải là không đồng bộ. Chạy xử lý async lambda chỉ là tốt. – Firoso

+2

Trong .Net 4.5 DP, dường như chỉ có 'Task.Run()', không có 'Ex'. – svick

+4

TaskEx chỉ có trong CTP. Trong .Net 4.5 các phương thức trên TaskEx đã được tích hợp vào Task. – Phil

1

Sự khác biệt giữa hai phương pháp DoWork() của bạn là phương pháp đầu tiên (sử dụng TaskEx.RunEx()) hoàn toàn không đồng bộ. Nó thực thi hoàn toàn đồng bộ, khởi động tác vụ khác trên một luồng khác, và ngay lập tức trả về Task hoàn thành. Nếu bạn await ed hoặc Wait() chỉnh sửa tác vụ đó, nó sẽ không đợi cho đến khi hoàn thành nhiệm vụ nội bộ.