多次调用 GetAsync 只执行一次

calling GetAsync multiple times only executes one time

我正在尝试在非阻塞异步函数中多次调用 GetAsync。令我惊讶的是,只有第一个调用被执行。所有请求都针对同一个域,因此我认为重用 HttpClient 是有意义的。为什么只执行第一个请求,我应该如何重写代码?

private static HttpClient client = new HttpClient(new HttpClientHandler(){UseProxy = false});

private static async Task NonblockingGet(string destination){
 client.Timeout = TimeSpan.FromSeconds(10);
 var result = await client.GetAsync(destination);
 // handle result
}


private static void CallMultipleTimes(){
 NonblockingGet("domain1/url1"); // only this one is executed
 NonblockingGet("domain1/url2");
 NonblockingGet("domain1/url3");
}

//main
ManualResetEvent mre = new ManualResetEvent(false);
CallMultipleTimes();
mre.WaitOne();

不,对 NonblockingGet 的所有三个调用都已执行。但是在第二次调用时,您试图在已经启动请求后修改 client(即设置超时)。这是不允许的,它会抛出一个 System.InvalidOperationException 异常(被默默忽略)

This instance has already started one or more requests. Properties can only be modified before sending the first request.

因此,第二个和第三个client.GetAsync()当然没有执行。

client.Timeout = TimeSpan.FromSeconds(10); 移动到 CallMultipleTimes() 中的第一个语句(或在第一个请求之前只执行一次的其他地方),一切都会按预期工作(至少对于这个用例).

private static async Task NonblockingGet(string destination){
 // client.Timeout = TimeSpan.FromSeconds(10); // <--- remove it here
 var result = await client.GetAsync(destination);
 // handle result
}


private static void CallMultipleTimes(){
  client.Timeout = TimeSpan.FromSeconds(10);  // <--- add it here
 NonblockingGet("domain1/url1"); // only this one is executed
 NonblockingGet("domain1/url2");
 NonblockingGet("domain1/url3");
}


我不明白为什么只执行第一个调用(我自己尝试了代码,所有调用都正确)。但是通常您不想将线程等待与异步代码混合使用。并且您希望在任务中等待和执行所有异步操作(为了正确的异常处理)。

这是我的提议

HttpClient client = new HttpClient(new HttpClientHandler() { UseProxy = false});

async Task NonblockingGet(string destination)
{
    client.Timeout = TimeSpan.FromSeconds(10);
    var result = await client.GetAsync(destination);
    // handle result
}


async Task CallMultipleTimes() =>
    await Task.WhenAll(NonblockingGet("domain1/url1"), NonblockingGet("domain1/url2"), NonblockingGet("domain1/url3"));


// Main
await CallMultipleTimes();
// If you are here all 3 operations requests are completed

注意:如果您使用的是 .Net < 6.0,则必须将 Main 函数签名从 static void 更改为 static async Task。