C# 如何使用Task.wheny并实施重试
我有一个解决方案,可以创建多个基于I/O的任务,我正在使用Task.WhenAny()来管理这些任务。但许多任务通常会由于网络问题或请求限制等原因而失败 在使用Task.WhenAny()方法时,我似乎找不到一个能够使我成功重试失败任务的解决方案 以下是我正在做的:C# 如何使用Task.wheny并实施重试,c#,async-await,C#,Async Await,我有一个解决方案,可以创建多个基于I/O的任务,我正在使用Task.WhenAny()来管理这些任务。但许多任务通常会由于网络问题或请求限制等原因而失败 在使用Task.WhenAny()方法时,我似乎找不到一个能够使我成功重试失败任务的解决方案 以下是我正在做的: var tasks = new List<Task<MyType>>(); foreach(var item in someCollection) { task.Add(GetSomethingAsyn
var tasks = new List<Task<MyType>>();
foreach(var item in someCollection)
{
task.Add(GetSomethingAsync());
}
while (tasks.Count > 0)
{
var child = await Task.WhenAny(tasks);
tasks.Remove(child);
???
}
var tasks=newlist();
foreach(someCollection中的变量项)
{
Add(GetSomethingAsync());
}
而(tasks.Count>0)
{
var child=wait Task.WhenAny(任务);
任务。删除(子项);
???
}
因此,上面的结构适用于完成任务,但我还没有找到处理和重试失败任务的方法。
等待任务。当任何
抛出聚合异常而不允许我检查任务状态时。在异常处理程序中,我不再有任何方法重试失败的任务 我相信在任务中重试,然后用任务替换任务。WhenAny
-in-a-loop反模式会更容易。WhenAll
例如,使用:
如果出于某种原因不想使用库,可以使用下面的
Retry
方法。它接受一个任务工厂,并继续创建任务,然后等待任务,直到任务成功完成,或者到达maxtures
:
public static async Task<TResult> Retry<TResult>(Func<Task<TResult>> taskFactory,
int maxAttempts)
{
int failedAttempts = 0;
while (true)
{
try
{
var task = taskFactory();
return await task.ConfigureAwait(false);
}
catch
{
failedAttempts++;
if (failedAttempts >= maxAttempts) throw;
}
}
}
输出:
Url:112276个字符Url:,122784个字符 如果取消对第三个url的注释,则在五次尝试失败后,将抛出一个
HttpRequestException
,而不是这些结果
该方法将在传播错误之前等待所有任务的完成。如果最好尽快报告错误,您可以找到有问题的解决方案。您能否澄清任务之间的区别?目前,您似乎有一个相同任务的列表。也许你正在传递给
GetSomethingAsync()
一些不同的参数?@Sergey,是的,我正在传递一个唯一的参数给GetSomethingAsync,我需要在重试任务时能够引用它。谢谢@Stephen,我会尝试一下。我和Polly在这方面做了些尝试,但仍然在使用等待任务。当任何一个模式都不起作用时。@macon:不,只是很尴尬。总有比使用任务更干净的解决方案。当任何任务完成时删除任务(最终等待它们全部完成)。对于传播所有异常的更复杂的实现,请查看。
var policy = ...; // See Polly documentation
var tasks = someCollection.Select(item => policy.ExecuteAsync(() => GetSomethingAsync()));
await Task.WhenAll(tasks);
public static async Task<TResult> Retry<TResult>(Func<Task<TResult>> taskFactory,
int maxAttempts)
{
int failedAttempts = 0;
while (true)
{
try
{
var task = taskFactory();
return await task.ConfigureAwait(false);
}
catch
{
failedAttempts++;
if (failedAttempts >= maxAttempts) throw;
}
}
}
string[] urls =
{
"https://stackoverflow.com",
"https://superuser.com",
//"https://no-such.url",
};
var httpClient = new HttpClient();
var tasks = urls.Select(url => Retry(async () =>
{
return (Url: url, Html: await httpClient.GetStringAsync(url));
}, maxAttempts: 5));
var results = await Task.WhenAll(tasks);
foreach (var result in results)
{
Console.WriteLine($"Url: {result.Url}, {result.Html.Length:#,0} chars");
}