У меня есть это базовое консольное приложение для парсинга на C #, которое асинхронно использует WebRequest для получения html из списка сайтов. Он работает нормально, но как мне настроить триггер, который срабатывает после обработки каждого сайта в списке?
Я потратил пару часов на изучение различных решений в Интернете, включая документы MS, но ни одно из них не дает прямого ответа через код. Я читал об IAsyncResult.AsyncWaitHandle, но понятия не имею, как интегрировать его в свой код. Я просто хотел бы вызвать пользовательскую функцию, когда все потоки завершат обработку или тайм-аут.
Одна уловка заключается в том, что я никогда не знаю заранее, сколько сайтов в моем списке (он определяется пользователем), поэтому мне нужно решение, достаточно надежное, чтобы ждать 5 событий для завершения 100 000 событий.
Спасибо. Рабочий код ниже:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;
namespace AsyncApp_01
{
class Program
{
static void Main(string[] args)
{
ArrayList alSites = new ArrayList();
alSites.Add("http://www.google.com");
alSites.Add("http://www.lostspires.com");
ScanSites(alSites);
Console.Read();
}
private static void ScanSites(ArrayList sites)
{
foreach (string uriString in sites)
{
WebRequest request = HttpWebRequest.Create(uriString);
request.Method = "GET";
object data = new object(); //container for our "Stuff"
// RequestState is a custom class to pass info to the callback
RequestState state = new RequestState(request, data, uriString);
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(UpdateItem), state);
//Register the timeout callback
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(ScanTimeoutCallback), state, (30 * 1000), true);
}
}
private static void UpdateItem(IAsyncResult result)
{
// grab the custom state object
RequestState state = (RequestState)result.AsyncState;
WebRequest request = (WebRequest)state.Request;
// get the Response
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
Stream s = (Stream)response.GetResponseStream();
StreamReader readStream = new StreamReader(s);
// dataString will hold the entire contents of the requested page if we need it.
string dataString = readStream.ReadToEnd();
response.Close();
s.Close();
readStream.Close();
Console.WriteLine(dataString);
}
private static void ScanTimeoutCallback(object state, bool timedOut)
{
if (timedOut)
{
RequestState reqState = (RequestState)state;
if (reqState != null)
{
reqState.Request.Abort();
}
Console.WriteLine("aborted- timeout");
}
}
class RequestState
{
public WebRequest Request; // holds the request
public object Data; // store any data in this
public string SiteUrl; // holds the UrlString to match up results (Database lookup, etc).
public RequestState(WebRequest request, object data, string siteUrl)
{
this.Request = request;
this.Data = data;
this.SiteUrl = siteUrl;
}
}
}
}
Бонусные баллы для всех, кто также может сказать мне, как ограничить количество одновременных потоков. Например, если мне нужно обработать 100 сайтов, как мне настроить его так, чтобы одновременно обрабатывались 10 сайтов, но не более. Я не хочу открывать 100 тем.