多线程应用的新手。
我正在尝试创建一个控制台应用程序来检查给定的IP地址列表(Intranet)。任何给定IP地址的每个网页都包含一些显示在html表格中的统计信息,我需要收集这些统计信息。 我可以在一个线程中执行此操作:设置请求/响应序列,获取页面内容并解析它。
我现在正在努力的是使这个多线程,因为我必须处理4000个IP地址和单线程需要一些时间。我有列表或字符串数组中的IP列表;你知道如何设置线程吗?
假设我有一个处理响应的函数,比如说," ProcessResponse(字符串s)",并且想要从10个线程开始,我可以从以下内容开始:
public class PASSServer
{
private string _ip;
public string IPAddress
{
get;
set;
}
public PASSServer()
{
}
}
static void Main(string[] args)
{
int iNumThreads = 3;
Thread[] threads = new Thread[iNumThreads];
string[] sIPs = { "192.168.10.20", "192.168.10.21", "192.168.10.22" };
for (int i = 0; i < threads.Length; i++)
{
ParameterizedThreadStart start = new ParameterizedThreadStart(Start);
threads[i] = new Thread(start);
PASSServer pserver = new PASSServer();
pserver.IPAddress = sIPs[i];
threads[i].Start(pserver);
}
Console.WriteLine("DONE");
Console.ReadKey();
}
static void Start(object info)
{
PASSServer pserver = (PASSServer)info;
crawl(pserver.IPAddress);
}
private static void crawl(string sUrl)
{
PASSData cData = new PASSData();
string sRequestUrl = "http://" + sUrl.Trim() + "/cgi-bin/sysstat?";
string sEncodingType = "utf-8";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sRequestUrl);
request.KeepAlive = true;
request.Timeout = 15 * 1000;
System.Net.HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string sStatus = ((HttpWebResponse)response).StatusDescription;
sEncodingType = GetEncodingType(response);
System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream(), Encoding.GetEncoding(sEncodingType));
// Read the content.
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
}
非常感谢任何帮助。
我没有使用多线程,但搜索了主题并得到了一些想法,只是不确定如何最好地设置我的场景。
答案 0 :(得分:2)
不要使用线程。使用异步HTTP请求。例如,使用HttpWebRequest.BeginGetResponse或HttpWebRequest.GetResponseAsync。使用Semaphore限制并发请求的数量。
所以,如果你有一个URL列表(一个List<string>
),并且你想要最多10个并发请求:
List<string> _urls = GetListOfUrls();
Semaphore _requestSemaphore = new Semaphore(10, 10);
foreach (var url in _urls)
{
// wait for an available spot
_requestSemaphore.WaitOne();
// Now start an asynchronous request with this url
var request = (HttpWebRequest)WebRequest.Create(url);
request.BeginGetResponse(GetResponseCallback, request);
}
当您的清单为空时,您必须等待收到最终答复。你这样做的方法是等待信号量10次。如果你有10个,那么就不会有任何未完成的请求:
for (int i = 0; i < 10; ++i)
{
_requestSemaphore.WaitOne();
}
您的回调,在收到回复时调用:
void GetResponseCallback(IAsyncResult ar)
{
var request = (HttpWebRequest)ar.AsyncState;
var response = (HttpWebResponse)request.EndGetResponse(ar);
// process the response here.
// when you're done processing the response, release the semaphore
_requestSemaphore.Release();
}
答案 1 :(得分:0)
我会遍历您的IP地址列表并启动ThreadPool工作项。
foreach(string addr in IpAddresses)
Threading.ThreadPool.QueueUserWorkItem(
(string ipaddr) =>
{
ResponseFromQuery resp = new ResponseFromQuery();
this.BeginInvoke(new MethodInvoker(() => { UpdateTable(resp); }));
}, addr);
*编辑:在上面,你需要调用BeginInvoke并创建一个methodinvoker,它在你的应用程序调用UpdateTable中回调一个新方法。您可以传递您的响应信息(无论它是什么类型,我都使用了一个组成的ResponseFromQuery类)。
您可以使用匿名函数,或者如果有很多代码并且您可以在其他地方使用它,您可以创建一个处理类和方法,您可以将其作为要执行的方法传递。
如果您想自己管理线程,可以创建一个Dictionary或List对象,并为集合中的每个项目添加一个线程:
Dictionary<string, Thread> _threads = new Dictionary<string, Thread>();
foreach (string addr in IpAddresses)
{
_threads.Add(addr, new System.Threading.Thread(
new System.Threading.ParameterizedThreadStart(
(object ip) =>
{
// process ip.
}, addr)));
_threads[addr].Start();
}