多线程http请求

时间:2012-03-06 22:30:04

标签: c# multithreading

我正在尝试创建一个类,以便在不同的线程上同时发送多个http请求,以尝试加快通过互联网获取多个文档。

我实现了这个,但是当我从1增加到2个线程时,执行时间加倍,从1到4个线程,执行时间翻两番。我认为它应该在超过1个线程上更快!

这是代码,也许我有一些奇怪的问题。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ComponentModel;

namespace scomA3proj
{
    public class MultithreadedHttpRequests_James : IMultithreadedHttpRequests_James
    {
        List<string> Urls;
        string[] responses;
        public List<string> getHttpResponses(List<string> urls, int numThreads)
        {
            this.Urls = urls;
            responses = new string[urls.Count];
            List<Thread> threads = new List<Thread>();
            for (int i = 0; i < numThreads; i++)
            {
                Thread bgw = new Thread(new ParameterizedThreadStart(bgw_DoWork));
                bgw.Start();
                threads.Add(bgw);
            }
            for (int i = 0; i < numThreads; i++)
            {
                threads[i].Join();
            }
            return responses.ToList();
        }

        void bgw_DoWork(object sender)
        {
            while (true)
            {
                int index = getNext();
                if (index == -1) break;
                string s = Urls[index];
                responses[index] = HttpRequestWrapper.getResponse(s);
            }
        }
        int counter = 0;
        int getNext()
        {
            int res = 0;
            lock (this)
            {
                res = counter;
                counter++;
            }
            if (res >= Urls.Count) 
                return -1;

            return res;
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;

namespace scomA3proj
{
    public sealed class HttpRequestWrapper
    {
        /// <summary>
        /// Gets the HTTP response from a web page. Headers are used based on the useHeaders flag.
        /// </summary>
        /// <param name="url">URI formatted URL(example:"http://www.yahoo.com").</param>
        /// <returns>Returns Html source of requested page.</returns>
        public static string getResponse(string url)
        {
            string result = "";
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                StreamReader reader = new StreamReader(response.GetResponseStream());
                result = reader.ReadToEnd();
            }
            catch (Exception ex)
            {
                result = "error";
            }
            return result;
        }
    }
}

更新: 我添加了这个,但它没有帮助

ServicePointManager.DefaultConnectionLimit = numThreads;

我想也许我连接到的网络路径(大学)限制为每台PC或某物的一个出站连接,并因请求多个而惩罚我...... idk ......

2 个答案:

答案 0 :(得分:1)

这里可能会发生一些事情,第一件事是您达到了网络请求允许的连接数限制。默认情况下,它设置为2,因此要更改它,在函数的开头,您可以将其更新为您正在使用的线程数。

ServicePointManager.DefaultConnectionLimit = 10; 
// 10 should match the number of threads you're executing

除此之外,它取决于您监控执行时间的位置。如果你正在监视整个执行时间,你应该注意你正在做的各种事情,比如实现你没有使用的队列。

答案 1 :(得分:0)

使用新的System.Net.Http.HttpClient,您可以轻松完成此操作而无需滚动自己的代码:

public class ThreadedHttpGetter
{
    public IEnumerable<Task<HttpResponseMessage>> GetResponses(IEnumerable<string> uris)
    {
        foreach (string uri in uris)
        {
            using (var httpClient = new HttpClient())
            {
                yield return httpClient.GetAsync(uri);
            }
        }
    }
}

使用以下代码对cnn.com运行10次迭代(如上所述):

    [Test]
    public void YieldResponse()
    {
        IEnumerable<Task<HttpResponseMessage>> responses = new ThreadedHttpGetter().GetResponses(Enumerable.Repeat(uri, iterations));
        Console.WriteLine(responses.Count());
    }

导致控制台输出:

10 测试跑了280ms

显然,这将取决于您的网络连接的容量和提供响应的网站。

更新

我偶然发现了Stephen Toub的这篇博客文章。这真的是你想要的,他甚至在他的评论中给出了一个具体的例子,详细描述了你的目标!

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