什么';s是使方法异步运行的最佳方法

本文关键字:方法 异步 运行 最佳 什么 | 更新日期: 2023-09-27 18:20:07

嗨,我是异步编程的新手。如何运行我的方法checkAvaible来运行async?如果可能的话,我想一次下载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);
        }
    }

什么';s是使方法异步运行的最佳方法

  1. 您不希望同时下载2500个页面,因为这对您的客户端和服务器都是一个问题。相反,我添加了并发下载限制(默认为10)。网页将被下载,每次10页。(或者,如果你运行的是超级计算机,你可以将其更改为2500:)
  2. Generic Lists(在您的情况下,我认为它是字符串列表)默认情况下不是线程安全的,因此您应该同步对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);
            }
        }
    }
}

最好从内部和外部将代码转换为async。遵循最佳实践,例如避免使用async void,使用Async后缀,并返回结果而不是修改共享变量:

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

然后,您可以使用Task.WhenAll:同时启动任意数量的

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