Я хочу сделать 10 асинхронных запросов HTTP сразу и только обработать результаты, когда все завершились и в отдельной функции обратного вызова. Я также не хочу блокировать любое использование потоков WaitAll (это - мое понимание, что блоки WaitAll, пока все не завершены). Я думаю, что хочу сделать пользовательский IAsyncResult, который обработает множественные вызовы. Я на правильном пути? Есть ли какие-либо хорошие ресурсы или примеры там, которые описывают обработку этого?
Мне нравится решение Дарина. Но если вы хотите что-то более традиционное, можете попробовать следующее.
Я бы определенно использовал массив обработчиков ожидания и механизм WaitAll:
static void Main(string[] args)
{
WaitCallback del = state =>
{
ManualResetEvent[] resetEvents = new ManualResetEvent[10];
WebClient[] clients = new WebClient[10];
Console.WriteLine("Starting requests");
for (int index = 0; index < 10; index++)
{
resetEvents[index] = new ManualResetEvent(false);
clients[index] = new WebClient();
clients[index].OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
clients[index].OpenReadAsync(new Uri(@"http:\\www.google.com"), resetEvents[index]);
}
bool succeeded = ManualResetEvent.WaitAll(resetEvents, 10000);
Complete(succeeded);
for (int index = 0; index < 10; index++)
{
resetEvents[index].Dispose();
clients[index].Dispose();
}
};
ThreadPool.QueueUserWorkItem(del);
Console.WriteLine("Waiting...");
Console.ReadKey();
}
static void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
// Do something with data...Then close the stream
e.Result.Close();
ManualResetEvent readCompletedEvent = (ManualResetEvent)e.UserState;
readCompletedEvent.Set();
Console.WriteLine("Received callback");
}
static void Complete(bool succeeded)
{
if (succeeded)
{
Console.WriteLine("Yeah!");
}
else
{
Console.WriteLine("Boohoo!");
}
}
Я думаю, вам лучше использовать подход WaitAll. В противном случае вы будете обрабатывать 10 обратных вызовов IAsyncResult и использовать семафор для определения того, что все 10 наконец-то завершены.
Помните, что WaitAll очень эффективен; он не похож на глупость, когда поток "спит". Когда поток спит, он продолжает использовать время обработки. Когда поток "снимается с расписания", потому что он попал в WaitAll, он больше не потребляет процессорное время. Это очень эффективно.
В .NET 4.0 есть хорошая параллельная библиотека задач , которая позволяет вам делать такие вещи, как:
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
class Program
{
public static void Main()
{
var urls = new[] { "http://www.google.com", "http://www.yahoo.com" };
Task.Factory.ContinueWhenAll(
urls.Select(url => Task.Factory.StartNew(u =>
{
using (var client = new WebClient())
{
return client.DownloadString((string)u);
}
}, url)).ToArray(),
tasks =>
{
var results = tasks.Select(t => t.Result);
foreach (var html in results)
{
Console.WriteLine(html);
}
});
Console.ReadLine();
}
}
Как вы можете видеть, для каждого URL в списке разные задачи запускается, и после завершения всех задач вызывается обратный вызов и передается результат всех задач.