2015-11-02 101 views
1

嗨,我是新的异步编程。我如何运行我的方法checkAvaible来运行异步?如果可能的话,我希望一次下载2500页,不要等到完成一个下载并开始另一个下载。我怎么做到的?使方法运行异步的最佳方式是什么?

private static void searchForLinks() 
    { 
     string url = "http://www.xxxx.pl/xxxx/?action=xxxx&id="; 


     for (int i = 0; i < 2500; i++) 
     { 
      string tmp = url; 
      tmp += Convert.ToString(i); 

      checkAvaible(tmp); // this method run async, do not wait while one page is downloading 
     } 

     Console.WriteLine(listOfUrls.Count()); 
     Console.ReadLine(); 
    } 

    private static async void checkAvaible(string url) 
    { 
     using (WebClient client = new WebClient()) 
     { 
      string htmlCode = client.DownloadString(url); 

      if (htmlCode.IndexOf("Brak takiego obiektu w naszej bazie!") == -1) 
       listOfUrls.Add(url); 
     } 
    } 
+0

虽然你已经将它标记为“async”,但是你的两种方法都是同步的。 –

+0

好的我已经编辑并从方法中删除了异步searchForLinks – Icet

+1

方法应该返回'async void'的唯一时间是GUI事件处理程序。 https://msdn.microsoft.com/en-us/magazine/jj991977.aspx – MickyD

回答

3
  1. 你不会想在同一时间下载2500页,因为这将是您的客户端和服务器的问题。相反,我添加了一个并发下载限制(默认为10)。网页将一次下载10页。 (或者如果你正在运行一台超级计算机,你可以将其改为2500))
  2. 通用列表(我认为它是你的情况下的一个字符串列表)默认情况下不是线程安全的,因此你应该同步对Add方法。我还补充说。

下面是更新的源代码与并发呼叫

private static List<string> listOfUrls = new List<string>(); 

private static void searchForLinks() 
{ 
    string url = "http://www.xxxx.pl/xxxx/?action=xxxx&id="; 

    int numberOfConcurrentDownloads = 10; 

    for (int i = 0; i < 2500; i += numberOfConcurrentDownloads) 
    { 
     List<Task> allDownloads = new List<Task>(); 
     for (int j = i; j < i + numberOfConcurrentDownloads; j++) 
     { 
      string tmp = url; 
      tmp += Convert.ToString(i); 
      allDownloads.Add(checkAvaible(tmp)); 
     } 
     Task.WaitAll(allDownloads.ToArray()); 
    } 

    Console.WriteLine(listOfUrls.Count()); 
    Console.ReadLine(); 
} 

private static async Task checkAvaible(string url) 
{ 
    using (WebClient client = new WebClient()) 
    { 
     string htmlCode = await client.DownloadStringTaskAsync(new Uri(url)); 

     if (htmlCode.IndexOf("Brak takiego obiektu w naszej bazie!") == -1) 
     { 
      lock (listOfUrls) 
      { 
       listOfUrls.Add(url); 
      } 
     } 
    } 
} 
1

这是最好从内部工作,继续出代码转换为async的配置量asynhcronously下载页面。同时使用Task.WhenAll

private static async Task<string> checkAvaibleAsync(string url) 
{ 
    using (var client = new HttpClient()) 
    { 
    string htmlCode = await client.GetStringAsync(url); 

    if (htmlCode.IndexOf("Brak takiego obiektu w naszej bazie!") == -1) 
     return url; 
    else 
     return null; 
    } 
} 

那么你可以开始任意数量的这些:按照沿途的最佳做法,如避免async void,使用Async后缀,并返回结果,而不是修改共享变量

private static async Task<string[]> searchForLinksAsync() 
{ 
    string url = "http://www.xxxx.pl/xxxx/?action=xxxx&id="; 

    var tasks = Enumerable.Range(0, 2500).Select(i => checkAvailableAsync(url + i)); 
    var results = await Task.WhenAll(tasks); 
    var listOfUrls = results.Where(x => x != null).ToArray(); 

    Console.WriteLine(listOfUrls.Length); 
    Console.ReadLine(); 
} 
相关问题