【问题标题】:multithreading program with webrequests c#带有webrequests的多线程程序c#
【发布时间】:2014-09-26 13:01:08
【问题描述】:

我想做多线程异步下载管理器。但是我在多线程方面遇到了问题。 一个线程可以正常工作,但是当我创建第二个线程时 - 什么也没有。 我认为 webrequest 的同步存在问题。我读了这个答案Multithreading a large number of web requests in c#,但我并不完全理解。现在的问题:如何修改代码以使用多线程(线程,线程池)。

班级DownloadableContent:

{
    private string url { get; set; }
    private string path { get; set; }
    private Stream streamResponse { get; set; }
    private Stream streamLocal { get; set; }
    private HttpWebRequest webRequest { get; set; }
    private HttpWebResponse webResponse { get; set; }

    public DownloadableContent(string url, string path)
    {
        this.url = url;
        this.path = path;
    }

    public void Download()
    {
        using (WebClient wcDownload = new WebClient())
        {
            try
            {
                webRequest = (HttpWebRequest)WebRequest.Create(url);                 
                webRequest.Credentials = CredentialCache.DefaultCredentials;
                webResponse = (HttpWebResponse)webRequest.GetResponse();
                Int64 fileSize = webResponse.ContentLength;
                streamResponse = wcDownload.OpenRead(url);
                streamLocal = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
                byte[] downBuffer = new byte[2048];     
                int bytesSize = 0;
                while ((bytesSize = streamResponse.Read(downBuffer, 0, downBuffer.Length)) > 0)
                {
                    streamLocal.Write(downBuffer, 0, bytesSize);
                }
            }
            finally
            {
                streamResponse.Close();
                streamLocal.Close();
            }
        }
    }       
}

还有班级main

DownloadableContent file = new DownloadableContent("url", @"path");  
Thread thread = new Thread(file.Download);
thread.Start();

【问题讨论】:

  • 您的代码非常混乱。您正在使用WebClient HttpWebRequest。因此,您为每个 URL 发出两个请求。您应该删除webRequestwebResponse,而只使用WebClient
  • 您遇到问题的原因很可能是您没有处理您正在创建的webRequestwebResponse 对象。我从经验中知道,这通常会在几个请求后导致事情停止工作。由于您没有使用它们,只需将它们从您的代码中删除即可。
  • 我只留下了一个代码 Webclient ,现在效果很好

标签: c# multithreading webrequest


【解决方案1】:

我能给你的最好建议是使用 TPL。这是微软提供的一个很好的管理线程库。我在我的代码中使用了这个来解决你的类似问题,基本上我必须下载 8000 个 url,开始正常过程需要 30 分钟。在我使用这个库后,同样的过程在 30 秒内完成。

TPL 链接

Task Parallel Library (TPL)

请看一下示例:

BookStore- GitHub

【讨论】:

    【解决方案2】:

    异步编程值得你一读 然后看看这个 http://msdn.microsoft.com/en-us/library/System.Net.WebClient_methods(v=vs.110).aspx 你有异步下载东西的方法。 还要看看 TPL 并避免线程 http://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx

    多读一点可能会帮助你避免很多头痛。

    这是一个简单的例子

    private static void Main(string[] args)
    {
        var urlsAndPaths = new Dictionary<string, string>();
        urlsAndPaths.Add("http://i.forbesimg.com/media/lists/people/lionel-messi_416x416.jpg","messi.jpg");
        urlsAndPaths.Add("http://sizzlingsuperstars.com/wp-content/uploads/2014/07/Cristiano-Ronaldo-2-480x309.jpg", "cristiano.jpg");            
        foreach (var kvp in urlsAndPaths)
        {
            var wc = new WebClient();
            wc.DownloadFileAsync(new Uri(kvp.Key),kvp.Value);
        }
        Console.ReadKey();
    }
    

    【讨论】:

    • 感谢您的回答,看起来正确,但程序条件是使用线程和线程池的“新线程中的新下载”(训练任务)。 (两种不同的实现方式)
    • 这是 .NET 新手的任务 :)
    【解决方案3】:

    根据您使用的 .NET 框架版本,您可以利用 Task 类。你可以这样做

        foreach (var uri in myCollection)
        {
            Task.Factory.StartNew(() =>
            {
                try
                {
                    using (System.Net.WebClient client = new System.Net.WebClient())
                    {
                        client.DownloadFileCompleted += (o, args) =>
                        {
                            //Do something with the download
                        };
                        client.DownloadFileAsync(uri);
    
                    }
                }
                catch (Exception ex)
                {
                    //Do something
                }
            });
        }
    

    【讨论】:

      【解决方案4】:

      您使用的是 .NET 4.5 吗?执行此操作的“新方法”是使用 Task.WhenAll,它可以让您的下载异步并行进行,但允许框架决定是否/何时将工作安排到线程池。

      var client = new System.Net.WebClient();
      await Task.WhenAll(urls.Select(url => {
          var path = ?? // build local path based on url?
          return client.DownloadFileAsync(url, path);
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-24
        • 2010-12-14
        • 2020-07-06
        • 1970-01-01
        相关资源
        最近更新 更多