C#具有一个回调的多个异步HttpRequest

C#具有一个回调的多个异步HttpRequest,c#,asynchronous,httprequest,C#,Asynchronous,Httprequest,我想一次发出10个异步http请求,并且只在所有请求都完成后在一个回调函数中处理结果。我也不想使用WaitAll阻止任何线程(据我所知,WaitAll会阻止所有线程,直到所有线程都完成为止)。我想我想做一个自定义IAsyncResult,它将处理多个调用。我走对了吗?有什么好的资源或例子来描述如何处理这个问题吗?我认为你最好使用WaitAll方法。否则,您将处理10个IAsyncResult回调,并使用信号量确定所有10个回调最终都已完成 记住,WaitAll是非常高效的;这与线程“睡眠”的愚蠢

我想一次发出10个异步http请求,并且只在所有请求都完成后在一个回调函数中处理结果。我也不想使用WaitAll阻止任何线程(据我所知,WaitAll会阻止所有线程,直到所有线程都完成为止)。我想我想做一个自定义IAsyncResult,它将处理多个调用。我走对了吗?有什么好的资源或例子来描述如何处理这个问题吗?

我认为你最好使用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都会启动一个不同的任务,一旦所有任务完成,就会调用回调并传递所有任务的结果。

我喜欢Darin的解决方案。但是,如果你想要更传统的东西,你可以试试这个

我肯定会使用一系列等待句柄和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!");
    }
}
static void Main(字符串[]args)
{
WaitCallback del=状态=>
{
ManualResetEvent[]resetEvents=新的ManualResetEvent[10];
WebClient[]客户端=新的WebClient[10];
Console.WriteLine(“启动请求”);
对于(int-index=0;index<10;index++)
{
resetEvents[索引]=新的ManualResetEvent(错误);
客户端[索引]=新的WebClient();
客户端[索引].OpenReadCompleted+=新的OpenReadCompletedEventHandler(客户端\u OpenReadCompleted);
客户端[index].OpenReadAsync(新Uri(@“http:\\www.google.com”)、resetEvents[index]);
}
bool successed=ManualResetEvent.WaitAll(resetEvents,10000);
完成(成功);
对于(int-index=0;index<10;index++)
{
resetEvents[index].Dispose();
客户端[index].Dispose();
}
};
ThreadPool.QueueUserWorkItem(del);
控制台。WriteLine(“等待…”);
Console.ReadKey();
}
静态无效客户端\u OpenReadCompleted(对象发送方,OpenReadCompletedEventArgs e)
{
//对数据执行某些操作…然后关闭流
e、 Result.Close();
ManualResetEvent readCompletedEvent=(ManualResetEvent)e.UserState;
readCompletedEvent.Set();
Console.WriteLine(“收到的回调”);
}
静态无效完成(bool成功)
{
如果(成功)
{
控制台。WriteLine(“耶!”);
}
其他的
{
控制台。WriteLine(“Boohoo!”);
}
}

此操作的上下文是什么?在网页内?这种事情在F#中几乎是微不足道的。用F#编写一个可以从C#代码调用的模块可能是值得的…@Keltex它将是web应用程序的一部分。你是说从多个网页请求数据吗?@Scott P我正在调用多个web服务函数。在将结果返回给用户之前,我需要所有结果。在IIS线程池的上下文中,它是指仍在使用的线程,还是像异步调用一样放回池中?实际上,它只是在单独的工作线程中进行同步调用。要解决这个问题,您应该使用
TaskFactory.fromsync
+
client.BeginGetResponse
。这样,I/O完成端口将在没有线程阻塞的情况下使用。