GetStringAsync with ContinueWith和WhenAll——不等待所有请求完成
本文关键字:请求 等待 with ContinueWith WhenAll GetStringAsync | 更新日期: 2023-09-27 17:49:28
我试图处理每个单独的请求,因为它完成了,这是GetStringAsync
之后在ContinueWith
中会发生的事情,然后当它们都完成了额外的处理。
然而,ContinueWith
似乎在WhenAll
上立即着火。看起来好像GetStringAsync
任务是错误的,但我不知道为什么。
当我使用WaitAll
而不是WhenAll
并且只是在WaitAll
之后添加我的处理时,我的请求工作得很好。但是当我把它改为WhenAll
时,它失败了。
using (var client = new HttpClient())
{
Task.WhenAll(services.Select(x =>
{
return client.GetStringAsync(x.Url).ContinueWith(response =>
{
Console.WriteLine(response.Result);
}, TaskContinuationOptions.AttachedToParent);
}).ToArray())
.ContinueWith(response =>
{
Console.WriteLine("All tasks completed");
});
}
在使用async-await
时不应该使用ContinueWith
和TaskContinuationOptions.AttachedToParent
。只使用async-await
,而不是:
async Task<IEnumerable<string>> SomeMethod(...)
{
using (var client = new HttpClient())
{
var ss = await Task.WhenAll(services.Select(async x =>
{
var s = await client.GetStringAsync(x.Url);
Console.WriteLine(response);
return s;
};
Console.WriteLine("All tasks completed");
return ss;
}
}
我发现了问题。我把它留在这里,以防有人来找类似的答案。我仍然需要await
的Task.WhenAll
方法。
using (var client = new HttpClient())
{
await Task.WhenAll(services.Select(x =>
{
return client.GetStringAsync(x.Url).ContinueWith(response =>
{
Console.WriteLine(response.Result);
}, TaskContinuationOptions.AttachedToParent);
}).ToArray())
.ContinueWith(response =>
{
Console.WriteLine("All tasks completed");
});
}
我仍然看到你的解决方案的几个问题:
-
删除using语句-你不想处理HttpClient
-
删除
ContinueWith
s -如果你正确使用await
,你不需要它们 -
这篇MSDN文章中描述的
Task.WhenAny
方法是在任务完成时处理任务的一种更干净的方法。
我会重写你的例子,像这样:
var client = new HttpClient();
var tasks = services.Select(x => client.GetStringAsync(x.Url)).ToList();
while (tasks.Count > 0)
{
var firstDone = await Task.WhenAny(tasks);
tasks.Remove(firstDone);
Console.WriteLine(await firstDone);
}
Console.WriteLine("All tasks completed");
编辑地址注释:
如果您需要在任务完成时访问service
对象,一种方法是将tasks
修改为Task<ObjectWithMoreData>
而不是Task<string>
的列表。注意,lambda被标记为async
,因此我们可以在其中添加await
:
var client = new HttpClient();
var tasks = services.Select(async x => new
{
Service = x,
ResponseText = await client.GetStringAsync(x.Url)
}).ToList();
while (tasks.Count > 0)
{
var firstDone = await Task.WhenAny(tasks);
tasks.Remove(firstDone);
var result = await firstDone;
Console.WriteLine(result.ResponseText);
// do something with result.Service
}
Console.WriteLine("All tasks completed");