2012-01-15 41 views
6

Tôi không thực sự hiểu tại sao awaitasync không cải thiện hiệu suất của mã của tôi ở đây like they're supposed to.Tại sao CTP không đồng bộ hoạt động kém?

Mặc dù hoài nghi, tôi nghĩ rằng trình biên dịch có nghĩa vụ phải viết lại phương pháp của tôi để tải xuống được thực hiện song song ... nhưng có vẻ như điều đó không thực sự xảy ra.
(tôi làm nhận ra rằng awaitasync không tạo chủ đề riêng biệt;? Tuy nhiên, hệ điều hành nên làm tải trong parallal, và gọi lại mã của tôi trong thread ban đầu - không nên nó)

Tôi có đang sử dụng asyncawait không đúng cách không? Cách thích hợp để sử dụng chúng là gì?

Code:

using System; 
using System.Net; 
using System.Threading; 
using System.Threading.Tasks; 

static class Program 
{ 
    static int SumPageSizesSync(string[] uris) 
    { 
     int total = 0; 
     var wc = new WebClient(); 
     foreach (var uri in uris) 
     { 
      total += wc.DownloadData(uri).Length; 
      Console.WriteLine("Received synchronized data..."); 
     } 
     return total; 
    } 

    static async Task<int> SumPageSizesAsync(string[] uris) 
    { 
     int total = 0; 
     var wc = new WebClient(); 
     foreach (var uri in uris) 
     { 
      var data = await wc.DownloadDataTaskAsync(uri); 
      Console.WriteLine("Received async'd CTP data..."); 
      total += data.Length; 
     } 
     return total; 
    } 

    static int SumPageSizesManual(string[] uris) 
    { 
     int total = 0; 
     int remaining = 0; 
     foreach (var uri in uris) 
     { 
      Interlocked.Increment(ref remaining); 
      var wc = new WebClient(); 
      wc.DownloadDataCompleted += (s, e) => 
      { 
       Console.WriteLine("Received manually async data..."); 
       Interlocked.Add(ref total, e.Result.Length); 
       Interlocked.Decrement(ref remaining); 
      }; 
      wc.DownloadDataAsync(new Uri(uri)); 
     } 
     while (remaining > 0) { Thread.Sleep(25); } 
     return total; 
    } 

    static void Main(string[] args) 
    { 
     var uris = new string[] 
     { 
      // Just found a slow site, to demonstrate the problem :) 
      "http://www.europeanchamber.com.cn/view/home", 
      "http://www.europeanchamber.com.cn/view/home", 
      "http://www.europeanchamber.com.cn/view/home", 
      "http://www.europeanchamber.com.cn/view/home", 
      "http://www.europeanchamber.com.cn/view/home", 
     }; 
     { 
      var start = Environment.TickCount; 
      SumPageSizesSync(uris); 
      Console.WriteLine("Synchronous: {0} milliseconds", Environment.TickCount - start); 
     } 
     { 
      var start = Environment.TickCount; 
      SumPageSizesManual(uris); 
      Console.WriteLine("Manual: {0} milliseconds", Environment.TickCount - start); 
     } 
     { 
      var start = Environment.TickCount; 
      SumPageSizesAsync(uris).Wait(); 
      Console.WriteLine("Async CTP: {0} milliseconds", Environment.TickCount - start); 
     } 
    } 
} 

Output:

Received synchronized data... 
Received synchronized data... 
Received synchronized data... 
Received synchronized data... 
Received synchronized data... 
Synchronous: 14336 milliseconds 
Received manually async data... 
Received manually async data... 
Received manually async data... 
Received manually async data... 
Received manually async data... 
Manual: 8627 milliseconds   // Almost twice as fast... 
Received async'd CTP data... 
Received async'd CTP data... 
Received async'd CTP data... 
Received async'd CTP data... 
Received async'd CTP data... 
Async CTP: 13073 milliseconds  // Why so slow?? 

Trả lời

10

Câu trả lời của Chris gần như đúng, nhưng giới thiệu một điều kiện chủng tộc và đồng bộ chặn trên tất cả các tác vụ.

Như một quy tắc chung, tốt nhất là không nên sử dụng tính năng tiếp tục công việc nếu bạn có sẵn await/async. Ngoài ra, không sử dụng WaitAny/WaitAll - số async tương đương là WhenAnyWhenAll.

tôi sẽ viết nó như thế này:

static async Task<int> SumPageSizesAsync(IEnumerable<string> uris) 
{ 
    // Start one Task<byte[]> for each download. 
    var tasks = uris.Select(uri => new WebClient().DownloadDataTaskAsync(uri)); 

    // Asynchronously wait for them all to complete. 
    var results = await TaskEx.WhenAll(tasks); 

    // Calculate the sum. 
    return results.Sum(result => result.Length); 
} 
+0

Oh huh, điều này có vẻ sạch hơn rất nhiều. =) Cảm ơn! – Mehrdad

1

tôi có thể bị hiểu sai mã của bạn, nhưng có vẻ như bạn đang tung ra một sợi nền để làm việc đọc async và sau đó ngay lập tức ngăn chặn, chờ đợi để hoàn thành. Không có gì về phần 'async' của mã của bạn thực sự là không đồng bộ. Hãy thử điều này:

static async Task<int> SumPageSizesAsync(string[] uris) 
{ 
    int total = 0; 
    var wc = new WebClient(); 
    var tasks = new List<Task<byte[]>>(); 
    foreach (var uri in uris) 
    { 
     tasks 
      .Add(wc.DownloadDataTaskAsync(uri).ContinueWith(() => { total += data.Length; 
     })); 
    } 
    Task.WaitAll(tasks); 
    return total; 
} 

Và sử dụng nó như sau:

{ 
     var start = Environment.TickCount; 
     await SumPageSizesAsync(uris); 
     Console.WriteLine("Async CTP: {0} milliseconds", Environment.TickCount - start); 
    } 

tôi có thể wrong- những thứ async là mới và tôi không 100% làm quen với nó- nhưng thời gian tương tự như đồng bộ hóa phiên bản dường như mang tôi ra ngoài.

+0

Hm ... vì vậy tôi đoán câu hỏi hợp lý sau đó là, * đúng * cách để làm điều đó là gì? – Mehrdad

+0

Đã chỉnh sửa để thêm cách tôi cho rằng nó hoạt động. Một lần nữa, có thể hoàn toàn sai. –

+0

Cảm ơn! Mặc dù tôi nghĩ rằng toàn bộ điểm "chờ đợi" là thay đổi phần còn lại của phương pháp thành kiểu chuyển tiếp liên tục (và toàn bộ điểm của CTP không đồng bộ là loại bỏ sự cần thiết cho quá nhiều hệ thống ống nước với các đại biểu/lambdas) ... điều này khác với ví dụ 'BeginInvoke' và whatnot, cái mà chúng ta đã có từ ít nhất là .NET 2.0? – Mehrdad

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