如何有效地多线程HttpWebRequests?

时间:2012-07-12 17:05:52

标签: c# .net multithreading httpwebrequest

我正在尝试多线程httpwebrequest。它不需要返回响应,我只需要尽快发送它们。目前我正在使用任务,但显然这不是最有效的处理方式,因为它使用您的系统规范来确定线程而不是连接速度。

所以我想我想问的是,根据连接速度而不是PC的内核数量,使用线程的最有效方法是什么。

由于

4 个答案:

答案 0 :(得分:6)

您可以使用BeginGetResponse()方法async WebRequest方法。

答案 1 :(得分:3)

默认情况下,允许.Net应用程序打开2个与Web服务器的连接。您可以通过设置此变量来增加数量

//Set the connection limit of HTTP
System.Net.ServicePointManager.DefaultConnectionLimit = 20;

使用常规调用或异步方法,使用HttpWebRequest / HttpWebResponse,必须从GetReponseStream()正确处理/关闭Stream。通过从GetResponseStream()关闭Stream,您的应用程序将在完成后终止HTTP连接。

例如,在下面的代码中,我从Web返回StreamReader

public static StreamReader LoadWeb(string URL)
    {
        if (!URL.StartsWith("http"))
        {
            URL = "http://" + URL;
        }

        HttpWebResponse myResponse = null;
        HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(new Uri(URL));

        System.IO.Stream myStream = null;
        StreamReader myStreamReader = null;
        myRequest.Method = "GET";
        myRequest.Proxy = null;
        myRequest.Timeout = 60000;
        myRequest.KeepAlive = false;
        try
        {
            myResponse = (HttpWebResponse)myRequest.GetResponse();
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show("Error : " + ex.Message);
            return null;
        }

        if (myResponse != null)
        {
            if (myResponse.StatusCode == System.Net.HttpStatusCode.OK)
            {
                myStream = myResponse.GetResponseStream();
                myStreamReader = new StreamReader(myStream);
            }
        }

        return myStreamReader;

    }

之后,我从LoadWeb函数返回

StreamReader reader = LoadWeb("http://www.google.com");
//...process the reader
//Finally, close the reader
if (reader != null)
     reader.Close(); //This line will terminate the HTTP connection

希望它有所帮助。

答案 2 :(得分:1)

我建议您构建一个工作队列,并在字典中跟踪正在运行的工作程序,并在运行完成后启动新工作程序。这使您可以调整活动工作人员的数量。它还为您提供了一组活跃的工作人员,以防您需要发送停止消息。

您需要将此添加到app.config以超过默认连接限制2:

<system.net>
<connectionManagement>
  <remove address="*"/>
  <add address="*" maxconnection="10" />
</connectionManagement>
</system.net>

在下面的示例中,我使用回调从队列中删除一个worker,并使用Monitor来清空等待的worker队列的清空。

using System;
using System.Collections.Generic;
using System.Threading;

namespace Demo
{
    class Program
    {
        static Queue<Worker> waitingWorkers = new Queue<Worker>();
        static Dictionary<int, Worker> activeWorkers = new Dictionary<int, Worker>();
        static int maxThreads = 10;
        static object waitLock = new object();

        static void Main(string[] args)
        {
            for (int i = 0; i < 100; i++)
            {
                waitingWorkers.Enqueue(new Worker(new WorkerDoneDelegate(WorkerDone)));
            }

            lock (waitLock)
            {
                while (waitingWorkers.Count > 0)
                {
                    if (activeWorkers.Count > maxThreads)
                    {
                        Monitor.Wait(waitLock);
                    }
                    Worker worker = waitingWorkers.Dequeue();
                    Thread thread = new Thread(worker.SendSomething);
                    thread.IsBackground = true;
                    activeWorkers[thread.ManagedThreadId] = worker;
                    thread.Start();
                }
            }
            Console.WriteLine("Queue empty");
            Console.ReadKey();
        }

        static void WorkerDone()
        {
            lock (waitLock)
            {
                activeWorkers.Remove(Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("Worker done - id=" + Thread.CurrentThread.ManagedThreadId.ToString());
                Monitor.Pulse(waitLock);
            }
        }

        public delegate void WorkerDoneDelegate();
        public class Worker
        {
            static Random rnd = new Random();

            WorkerDoneDelegate Done;

            public Worker(WorkerDoneDelegate workerDoneArg)
            {
                Done = workerDoneArg;
            }

            public void SendSomething()
            {
                Console.WriteLine("Worker send - id=" + Thread.CurrentThread.ManagedThreadId.ToString());
                Thread.Sleep(rnd.Next(1, 1000));
                Done();
            }
        }
    }
}

答案 3 :(得分:0)

或者只是使用Parallel.For / ForEach它会为你做线程优化(选择池大小,线程数等等)。)