2013-07-12 23 views
11

Kısa bir süre önce, async/await çağrıları için bir daraltma ipliği örneği ile karşılaştım. Makinemdeki kodu analiz edip oynadıktan sonra, aynı şeyi yapmanın biraz farklı bir yolunu buldum. Belirsiz olduğum şey, kaputun altında olup bitenlerin hemen hemen aynı ya da dikkat çekici bir farklılık varsa mı? BuradaAsync/await ile Semaphore ipliği kısma

private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5); 

public async Task CallThrottledTasks() 
{ 
    var tasks = new List<Task>(); 

    for (int count = 1; count <= 20; count++) 
    { 
     await _semaphore.WaitAsync(); 

     tasks.Add(Task.Run(async() => 
      { 
       try 
       { 
        int result = await LongRunningTask(); 
        Debug.Print(result.ToString()); 
       } 
       finally 
       { 
        _semaphore.Release(); 
       } 
      })); 
    } 

    await Task.WhenAll(tasks); 

    Debug.Print("Finished CallThrottledTasks"); 
} 

Ve aynı kod almak benim:

Burada orijinal örneğine dayanarak kod ben kapalı yol muhtemelen değilim

private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5); 

public async Task CallThrottledTasks() 
{ 
    var tasks = new List<Task>(); 

    for (int count = 1; count <= 20; count++) 
    { 
     await _semaphore.WaitAsync(); 

     tasks.Add(LongRunningTask().ContinueWith(t => 
     { 
      try 
      { 
       int result = t.Result; 
       Debug.Print(result.ToString()); 
      } 
      finally 
      { 
       _semaphore.Release(); 
      } 
     })); 
    } 

    await Task.WhenAll(tasks); 

    Debug.Print("Finished CallThrottledTasks"); 
} 

ama O Görev gibi görünüyor. Çalıştırma yaklaşımı, LongRunningTask() işlevini çalıştırmak için bir görev oluşturuyor ve sonra da benim yaklaşımımı, Task.Run tarafından oluşturulan görevi atlayıp sonuçta biraz daha zayıf olduğu halde, sonucu yazdırmak için bir devamlılık yaratıyor. Bu doğru mu yoksa üssü yok muyum?

cevap

12

Çok az değil, sadece biraz. Genellikle async kodunda ContinueWith kodundan sakınıyorum ve daha async tane dostu varsayılan semantik. Öncelikle geliştirici zamanını optimize edin, ardından diğer konular için optimize edin.

Kodunuz, semantiği biraz değiştirir: orijinal kodda, LongRunningTask bir iş parçacığı havuzu bağlamından yürütüldü ve kodunuzda CallThrottledTasks içeriği ne olursa olsun çalıştırılır. Ayrıca, kodunuz LongRunningTask arasındaki istisnaları temiz bir şekilde yaymaz; Task<T>.Result, AggregateException'daki istisnaları sarmaya devam ederken, await hiçbir kaydırma yapmaz.

+0

Teşekkür ederiz. Bu tam olarak aradığım şey: çatlaklardan kaybolan uygulama yan etkileri. Async-beklemeyle pek çok şey var gibi geliyor. İstisnaların nasıl ele alındığına dair bacak çalışması yapacağım. TPL'den AggregateException'ı tanıyorum ama bununla yeteri kadar elimde olmadı. – AFM

+2

Aslında, TPL'den çok nadiren - "async" ile yararlı olan, ancak daha çok sadece yoldan değil, daha çok artık bir durum söz konusudur. Örneğin, "Görev" yapıcısı, "Başlat", "Bekle", "Sonuç", "Devam Etme", "Bekle" ve "Bekle", * paralel * (* senkronize olmayan *) programlama için tasarlanmıştır ve bunlardan kaçınılmalıdır. Ne yaptığınızı bilmedikçe "async" dünyası. –

İlgili konular