2013-10-04 41 views
8

DÜZENLEMEuyumsuz ve paralel dosya indirme

ben vardı sorunu değil, aynı zamanda kolayca bunu başarmak için nasıl bir yanıt yansıtacak şekilde sorunun başlığını değiştirdik.


Ben 1 yönteminde olduğu gibi Task<TResult> yerine Task dönmek 2 yöntem yapmaya çalışıyorum ama bunu düzeltmeye çalışıyorum sonucunda hataların bir çağlayan alıyorum.

  • Ben bu yüzden
  • altına return null eklendi altında bir return ifadesi eklemek Ama şimdi select ifadesi o sorgusu
  • gelen tür bağımsız değişkeni çıkaramayacağı anlamına şikayet etmemi istediği Buna karşılık await body(partition.Current);
  • önce return eklendi
  • Task.Run'u Task.Run<TResult> olarak değiştirdim, ancak başarılı olmaksızın.

Nasıl düzeltebilirim?

İlk yöntem http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx'dan geliyor, ikinci yöntem oluşturmaya çalıştığım aşırı yüklenmedir.

public static class Extensions 
{ 
    public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body) 
    { 
     return Task.WhenAll(
      from partition in Partitioner.Create(source).GetPartitions(dop) 
      select Task.Run(async delegate 
      { 
       using (partition) 
        while (partition.MoveNext()) 
         await body(partition.Current); 
      })); 
    } 

    public static Task ForEachAsync<T, TResult>(this IEnumerable<T> source, int dop, Func<T, Task<TResult>> body) 
    { 
     return Task.WhenAll(
      from partition in Partitioner.Create(source).GetPartitions(dop) 
      select Task.Run(async delegate 
      { 
       using (partition) 
        while (partition.MoveNext()) 
         await body(partition.Current); 
      })); 
    } 
} 

Kullanım örneği: Bu yöntemle

Ben uyumsuz paralel ve birden çok dosyayı indirmek istediğiniz: Ben ve burada göndermeden çözüldü

private async void MainWindow_Loaded(object sender, RoutedEventArgs e) 
{ 
    Artist artist = await GetArtist(); 
    IEnumerable<string> enumerable = artist.Reviews.Select(s => s.ImageUrl); 
    string[] downloadFile = await DownloadFiles(enumerable); 
} 

public static async Task<string[]> DownloadFiles(IEnumerable<string> enumerable) 
{ 
    if (enumerable == null) throw new ArgumentNullException("enumerable"); 
    await enumerable.ForEachAsync(5, s => DownloadFile(s)); 
    // Incomplete, the above statement is void and can't be returned 
} 

public static async Task<string> DownloadFile(string address) 
{ 
    /* Download a file from specified address, 
     * return destination file name on success or null on failure */ 

    if (address == null) 
    { 
     return null; 
    } 

    Uri result; 
    if (!Uri.TryCreate(address, UriKind.Absolute, out result)) 
    { 
     Debug.WriteLine(string.Format("Couldn't create URI from specified address: {0}", address)); 
     return null; 
    } 

    try 
    { 
     using (var client = new WebClient()) 
     { 
      string fileName = Path.GetTempFileName(); 
      await client.DownloadFileTaskAsync(address, fileName); 
      Debug.WriteLine(string.Format("Downloaded file saved to: {0} ({1})", fileName, address)); 
      return fileName; 
     } 
    } 
    catch (WebException webException) 
    { 
     Debug.WriteLine(string.Format("Couldn't download file from specified address: {0}", webException.Message)); 
     return null; 
    } 
} 
+1

Sonuçların ne olacağını umduğunuz hiç de net değil. T 'değerlerinin bir dizisini geçiyorsunuz ve her ikisinde de aynı işlevi yerine getiriyorsunuz - Görev 'dan ne tür bir sonuç elde etmeyi bekliyorsunuz? –

+0

Bir Görev almak istiyorum, bu soruya bir örnek ekledim. – Aybe

+0

* "Bu yöntemle paralel ve senkronize olmayan birden fazla dosya indirmek istiyorum" *: 'Paralel.Foreach' yeterli değil mi? –

cevap

23

, herkes sahip yardımcı olabilecek aynı sorun.

İlk gereksinim, görüntüleri hızlı bir şekilde karşıdan yükleyen küçük bir yardımcı oldu, ancak sunucu hızlı bir şekilde yanıt vermiyorsa bağlantıyı da bırakın, tüm bu , paralel ve eşzamansız olarak.

Bu yardımcı, sizden biri varsa, uzak yolu, yerel yolu ve özel durumu içeren bir tuple döndürecektir; Hatalı indirmelerin neden arızalı olduğunu bilmek her zaman iyi olduğu için oldukça kullanışlıdır. İndirmek için oluşabilecek durumlardan hiçbirini unuttuğumu düşünüyorum ama yorum yapmaya davetlisiniz. değil bir sen

  • İsteğe indirme işlemini iptal etme bir süre (kullanışlı için oluşturulacak eğer

    • Sen
    • Bunu kaydedilecektir yerel bir dosya adı belirtebilirsiniz indirmek için URL'lerin listesini belirtebilirsiniz

    ) yavaş veya ulaşılamayan sunucu için sadece DownloadFileTaskAsync kendisini kullanmak veya paralel ve asenkron indirme için ForEachAsync yardımcı kullanabilirsiniz. Bunu nasıl kullanılacağı hakkında bir örnekle

    Kodu:

    private async void MainWindow_Loaded(object sender, RoutedEventArgs e) 
    { 
        IEnumerable<string> enumerable = your urls here; 
        var results = new List<Tuple<string, string, Exception>>(); 
        await enumerable.ForEachAsync(s => DownloadFileTaskAsync(s, null, 1000), (url, t) => results.Add(t)); 
    } 
    
    /// <summary> 
    ///  Downloads a file from a specified Internet address. 
    /// </summary> 
    /// <param name="remotePath">Internet address of the file to download.</param> 
    /// <param name="localPath"> 
    ///  Local file name where to store the content of the download, if null a temporary file name will 
    ///  be generated. 
    /// </param> 
    /// <param name="timeOut">Duration in miliseconds before cancelling the operation.</param> 
    /// <returns>A tuple containing the remote path, the local path and an exception if one occurred.</returns> 
    private static async Task<Tuple<string, string, Exception>> DownloadFileTaskAsync(string remotePath, 
        string localPath = null, int timeOut = 3000) 
    { 
        try 
        { 
         if (remotePath == null) 
         { 
          Debug.WriteLine("DownloadFileTaskAsync (null remote path): skipping"); 
          throw new ArgumentNullException("remotePath"); 
         } 
    
         if (localPath == null) 
         { 
          Debug.WriteLine(
           string.Format(
            "DownloadFileTaskAsync (null local path): generating a temporary file name for {0}", 
            remotePath)); 
          localPath = Path.GetTempFileName(); 
         } 
    
         using (var client = new WebClient()) 
         { 
          TimerCallback timerCallback = c => 
          { 
           var webClient = (WebClient) c; 
           if (!webClient.IsBusy) return; 
           webClient.CancelAsync(); 
           Debug.WriteLine(string.Format("DownloadFileTaskAsync (time out due): {0}", remotePath)); 
          }; 
          using (var timer = new Timer(timerCallback, client, timeOut, Timeout.Infinite)) 
          { 
           await client.DownloadFileTaskAsync(remotePath, localPath); 
          } 
          Debug.WriteLine(string.Format("DownloadFileTaskAsync (downloaded): {0}", remotePath)); 
          return new Tuple<string, string, Exception>(remotePath, localPath, null); 
         } 
        } 
        catch (Exception ex) 
        { 
         return new Tuple<string, string, Exception>(remotePath, null, ex); 
        } 
    } 
    
    public static class Extensions 
    { 
        public static Task ForEachAsync<TSource, TResult>(
         this IEnumerable<TSource> source, 
         Func<TSource, Task<TResult>> taskSelector, Action<TSource, TResult> resultProcessor) 
        { 
         var oneAtATime = new SemaphoreSlim(5, 10); 
         return Task.WhenAll(
          from item in source 
          select ProcessAsync(item, taskSelector, resultProcessor, oneAtATime)); 
        } 
    
        private static async Task ProcessAsync<TSource, TResult>(
         TSource item, 
         Func<TSource, Task<TResult>> taskSelector, Action<TSource, TResult> resultProcessor, 
         SemaphoreSlim oneAtATime) 
        { 
         TResult result = await taskSelector(item); 
         await oneAtATime.WaitAsync(); 
         try 
         { 
          resultProcessor(item, result); 
         } 
         finally 
         { 
          oneAtATime.Release(); 
         } 
        } 
    } 
    

    Ben paralellik düzeyini seçme ForEachAsync imzasını değişmedim, ben istediğiniz gibi ayarlamak bildireceğiz.

    Çıktı örneği:

    :

    DownloadFileTaskAsync (null local path): generating a temporary file name for http://cache.thephoenix.com/secure/uploadedImages/The_Phoenix/Music/CD_Review/main_OTR_Britney480.jpg 
    DownloadFileTaskAsync (null local path): generating a temporary file name for http://ssimg.soundspike.com/artists/britneyspears_femmefatale_cd.jpg 
    DownloadFileTaskAsync (null local path): generating a temporary file name for http://a323.yahoofs.com/ymg/albumreviewsuk__1/albumreviewsuk-526650850-1301400550.jpg?ymm_1xEDE5bu0tMi 
    DownloadFileTaskAsync (null remote path): skipping 
    DownloadFileTaskAsync (time out due): http://hangout.altsounds.com/geek/gars/images/3/9/8/5/2375.jpg 
    DownloadFileTaskAsync (time out due): http://www.beat.com.au/sites/default/files/imagecache/630_315sr/images/article/header/2011/april/britney-spears-femme-fatale.jpg 
    DownloadFileTaskAsync (time out due): http://cache.thephoenix.com/secure/uploadedImages/The_Phoenix/Music/CD_Review/main_OTR_Britney480.jpg 
    DownloadFileTaskAsync (downloaded): http://newblog.thecmuwebsite.com/wp-content/uploads/2009/12/britneyspears1.jpg 
    DownloadFileTaskAsync (downloaded): http://newblog.thecmuwebsite.com/wp-content/uploads/2009/12/britneyspears1.jpg 
    DownloadFileTaskAsync (downloaded): http://static.guim.co.uk/sys-images/Music/Pix/site_furniture/2011/3/22/1300816812640/Femme-Fatale.jpg 
    DownloadFileTaskAsync (downloaded): http://www.sputnikmusic.com/images/albums/72328.jpg 
    

    1 dakika kadar sürebilir için kullanılan Şimdi ne zorlukla aynı sonucu :) bu 2 mesajların yazarına

    Ve büyük teşekkür 10 saniye sürer

    http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx

    http://blogs.msdn.com/b/pfxteam/archive/2012/03/04/10277325.aspx

  • +1

    Mükemmel uzatma yöntemleri! – nullable

    +0

    Evet, çok yardımcı oldular, teşekkürler! – Aybe

    +1

    İyi iş efendim :) –