我正在尝试对 httpwebrequest 进行多线程处理。它不需要返回响应,我只需要尽快将它们发送出去。目前我正在使用任务,但显然这不是最有效的做事方式,因为它使用您的系统规格来确定线程而不是连接速度。
所以我想我想问的是基于连接速度而不是你的电脑拥有的核心数量使用线程的最有效方法是什么。
谢谢
我正在尝试对 httpwebrequest 进行多线程处理。它不需要返回响应,我只需要尽快将它们发送出去。目前我正在使用任务,但显然这不是最有效的做事方式,因为它使用您的系统规格来确定线程而不是连接速度。
所以我想我想问的是基于连接速度而不是你的电脑拥有的核心数量使用线程的最有效方法是什么。
谢谢
您可以使用BeginGetResponse()
方法,它async
是WebRequest
.
默认情况下,.Net 应用程序允许打开 2 个到 Web 服务器的连接。您可以通过设置此变量来增加数量
//Set the connection limit of HTTP
System.Net.ServicePointManager.DefaultConnectionLimit = 20;
使用常规调用或异步方法,使用 HttpWebRequest/HttpWebResponse,您必须正确处理/关闭来自 GetReponseStream() 的流。通过从 GetResponseStream() 关闭 Stream,您的应用程序将在完成后终止 HTTP 连接。
例如,在下面的代码中,我从网络返回 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
希望能帮助到你。
我建议你建立一个工人队列并在字典中跟踪正在运行的工人,在运行的工人完成时启动新的工人。这使您可以调整活跃工作人员的数量。它还为您提供了一组活跃的工作人员,以防您需要向他们发送停止消息。
您需要将此添加到您的 app.config 以超过两个的默认连接限制:
<system.net>
<connectionManagement>
<remove address="*"/>
<add address="*" maxconnection="10" />
</connectionManagement>
</system.net>
在下面的示例中,我使用回调从队列中删除一个工作人员,并使用 aMonitor
来控制等待工作人员队列的清空。
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();
}
}
}
}
或者简单地使用 Parallel.For/ForEach 它将为您进行线程优化(选择池大小、线程数等):)