嵌套异步下载 - 异步中的异步

时间:2016-04-24 19:28:40

标签: c# winforms asynchronous download async-await

我有一些嵌套的异步方法相互调用,这让人感到困惑。我正在尝试转换一个以异步下载方式下载文件的项目。 点击下载按钮,这是触发的方法:

private async void enableOfflineModeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            for(int i = 0; i < _playlists.Count; i++)
            {
                DoubleDimList.Add(new List<String>());
                for(int j = 0; j < 5; j++)
                {
                    string sMp3 = IniReadValue(_playlists[i], "Track " + j);
                    DoubleDimList[i].Add(sMp3);
                }
                await Task.Run(() =>  _InetGetHTMLSearchAsyncs(DoubleDimList[i]));              
            }
        }

它会创建一个2d List,最后看起来像DoubleDimList[3][20]。 在每个sublist结束时,我正在进行async下载,如您所见。该方法看起来像这样

private async Task _InetGetHTMLSearchAsyncs(List<string> urlList)
        {
            foreach (var url in urlList)
            {
                await Task.Run(() => _InetGetHTMLSearchAsync(url));
            }
        }

_InetGetHTMLSearchAsync方法看起来像这样,这里就变得棘手了

private async Task _InetGetHTMLSearchAsync(string sTitle)
        {
            Runs++;
            if (AudioDumpQuery == string.Empty)
            {
                //return string.Empty;
            }
            string sResearchURL = "http://www.audiodump.biz/music.html?" + AudioDumpQuery + sTitle.Replace(" ", "+");
            try
            {
                using (var client = new WebClient())
                {
                    client.Headers.Add("Referer", @"http://www.audiodump.com/");
                    client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A");
                    client.DownloadStringCompleted += Client_DownloadStringCompleted;
                    await Task.Run(() => client.DownloadStringAsync(new Uri(sResearchURL)));

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Debug message: " + ex.Message + "InnerEx: " + ex.StackTrace);
                Console.WriteLine("Runs: " + Runs);
                return;
            }
        }

Client_DownloadStringCompleted上,有一个名为async的方法。这是

private async void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            string[] sStringArray;
            string aRet = e.Result;
            string[] aTable = _StringBetween(aRet, "<BR><table", "table><BR>", RegexOptions.Singleline);
            if (aTable != null)
            {
                string[] aInfos = _StringBetween(aTable[0], ". <a href=\"", "<a href=\"");
                if (aInfos != null)
                {
                    for (int i = 0; i < 1; i++)
                    {
                        sStringArray = aInfos[i].Split('*');
                        sStringArray[0] = sStringArray[0].Replace("&#39;", "'");
                        aLinks.Add(sStringArray[0]);
                    }
                    await Task.Run(() => DownloadFile(aLinks[FilesDownloaded]));
                }
            }
        }

从那里,惊喜!另一个async电话。

private async Task DownloadFile(string url)
        {
            try
            {
                using (var client = new WebClient())
                {
                    client.Headers.Add("Referer", @"http://www.audiodump.biz/");
                    client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A");
                    client.DownloadFileCompleted += Client_DownloadFileCompleted;
                    await Task.Run(() => client.DownloadFileTaskAsync(url, mp3Path + "\\" + count + ".mp3"));

                }
            }
            catch (Exception Ex)
            {
                Console.WriteLine("File download error: " + Ex.StackTrace);
            }
        }

现在,创建2d List之后的第一部分是检索mp3的下载链接。第二部分是在提供有效URL后立即下载mp3。它的工作原理却奇怪。而不是正常下载文件(第1,第2,第3 ......),它将随机下载文件(第1,第5,第8 ......)。

这是我第一次去async下载和男孩,我已经远离我的极限了。

我在哪里弄乱这个?而主要的问题是,它会以它应该的方式工作吗?

1 个答案:

答案 0 :(得分:1)

你的代码看起来很不错,除了两件事:

  1. 您不应该使用Task.RunTask.Run的主要用例是从GUI线程移动CPU绑定的工作,因此它不会阻止UI。我有一个关于proper use of Task.Run的系列文章,详细介绍了这一点。
  2. 您应该使用一致的异步模式,理想情况为TAP。您的代码目前正在{em>除之外的所有地方使用TAP,_InetGetHTMLSearchAsync正在使用EAP。这就是造成你所看到的奇怪行为的原因。
  3. 固定的_InetGetHTMLSearchAsync看起来像这样:

    private async Task _InetGetHTMLSearchAsync(string sTitle)
    {
      Runs++;
      string sResearchURL = "http://www.audiodump.biz/music.html?" + AudioDumpQuery + sTitle.Replace(" ", "+");
      try
      {
        using (var client = new WebClient())
        {
          client.Headers.Add("Referer", @"http://www.audiodump.com/");
          client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A");
          string[] sStringArray;
          string aRet = await client.DownloadStringTaskAsync(new Uri(sResearchURL));
          string[] aTable = _StringBetween(aRet, "<BR><table", "table><BR>", RegexOptions.Singleline);
          if (aTable != null)
          {
            string[] aInfos = _StringBetween(aTable[0], ". <a href=\"", "<a href=\"");
            if (aInfos != null)
            {
              for (int i = 0; i < 1; i++)
              {
                sStringArray = aInfos[i].Split('*');
                sStringArray[0] = sStringArray[0].Replace("&#39;", "'");
                aLinks.Add(sStringArray[0]);
              }
              await DownloadFile(aLinks[FilesDownloaded]); // Should really be called "DownloadFileAsync"
            }
          }
        }
      }
      catch (Exception ex)
      {
        Console.WriteLine("Debug message: " + ex.Message + "InnerEx: " + ex.StackTrace);
        Console.WriteLine("Runs: " + Runs);
        return;
      }
    }