2012-01-15 18 views
6

Neden await ve async kodunun neden performansımı iyileştirmediğini anlamıyorum like they're supposed to.Async CTP neden yetersiz performans gösteriyor?

Şüpheli olsa da, derleyicinin yöntemimi yeniden yazması gerektiğine inanıyorum, böylece indirmeler paralel olarak yapıldı ... ama gerçekte olmuyor gibi görünüyor.
(Benawait ve async ayrı konuları oluşturmadığından emin farkında mısın ;? Ancak OS parallal indirme işlemlerini yapıyor ve orijinal dizisindeki kodumu geri çağırma olmalıdır - gerektiğini değil o)

async ve await yanlış kullanıyor muyum? Onları kullanmanın doğru yolu nedir?

Kodu:

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); 
     } 
    } 
} 

Çıktı:

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?? 

cevap

10

Chris'in cevabı hemen hemen doğru, ancak bir yarış durumu getiriyor ve tüm görevler üzerinde eşzamanlı olarak blok oluşturuyor.

Genel kural olarak, await/async ürününüz varsa, görev sürekliliğini kullanmamak en iyisidir. Ayrıca, WaitAny/WaitAll kullanmayın - async eşdeğerleri WhenAny ve WhenAll.

böyle yazarsınız: ...

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

Ah, bu çok daha temiz görünüyor. =) Teşekkürler! – Mehrdad

1

Ben kodunuzu misreading olabilir, ancak bekleyen, zaman uyumsuz okuma yapmak için bir arka plan iş parçacığı başlatılması ve daha sonra hemen engelliyor gibi görünüyor tamamlaması için. Kodunuzun 'async' kısmı hakkında bir şey aslında asenkron değildir.

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; 
} 

Ve böylece kullanmak: Bu deneyin

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

Ben zaman uyumsuz şeyler yenidir yanlış tipi olabilirdi ve ben It- ama senkron benzer zamanlama ile% 100 aşina değilim versiyonu beni ayıracak gibi görünüyor.

+0

Hm yüzden o is mantıklı soruyu tahmin yapmak * Doğru * yolu nedir? – Mehrdad

+0

Nasıl çalıştığını düşündüğümü eklemek için düzenlenmiştir. Yine, tamamen yanlış olabilir. –

+0

Teşekkürler! “Beklemenin” tüm noktasını, yöntemin geri kalanını stilin sürekliliğine dönüştürmek olduğunu düşünmeme rağmen (ve asenkron CTP'nin bütün noktası, delegeler/lambdalarla çok fazla sıhhi tesisat ihtiyacını ortadan kaldırmaktır) ... nasıl bu, örn. 'BeginInvoke' ve whatnot, şimdiden en azından .NET 2.0’dan beri ne vardı? – Mehrdad