#c# #async-await #task-parallel-library #polly
#c# #асинхронное ожидание #задача-параллельная-библиотека #polly
Вопрос:
Допустим, у меня есть список объектов myObjs
типа List<Foo>
.
У меня есть политика polly :
var policy = Policy.Handle<Exception>().RetryForever();
для которых я хочу запускать методы в parralel, но продолжаю повторять каждый из них по мере их сбоя.
for (int i = 0; i < myObjs.Count; i )
{
var obj = myObjs[i];
policy.Execute(() => Task.Factory.StartNew(() => obj.Do(), TaskCreationOptions.LongRunning));
}
Будет ли это вызываться параллельно и повторять каждый объект? Итак, если myObjs[5].do()
произойдет сбой, будет ли повторен только этот запуск, в то время как другие объекты выполняются только один раз?
Кроме того, должен ли я использовать ExecuteAsync()
метод, который принимает Func<Task>
вместо Execute(Action)
того, который показан в примере? Do()
это просто синхронный метод, запускаемый в отдельном потоке. Фактический код выглядит следующим образом, где each()
это просто foreach wrapper()
_consumers.ForEach(c => policy.Execute(() => Task.Factory.StartNew(() => c.Consume(startFromBeg), TaskCreationOptions.LongRunning)));
Редактировать:
Я попробовал код:
class Foo
{
private int _i;
public Foo(int i)
{
_i = i;
}
public void Do()
{
//var rnd = new Random();
if (_i==2)
{
Console.WriteLine("err" _i);
throw new Exception();
}
Console.WriteLine(_i);
}
}
var policy = Policy.Handle<Exception>().Retry(3);
var foos=Enumerable.Range(0, 5).Select(x => new Foo(x)).ToList();
foos.ForEach(c => policy.Execute(() => Task.Factory.StartNew(() => c.Do(), TaskCreationOptions.LongRunning)));
но я получаю результат:
0 1 ошибка 2 3 4 5
Я думал, что это повторит попытку 2 еще несколько раз, но этого не происходит. Есть идеи, почему?
Ответ №1:
Кто бы ни владел задачами, он должен каким-то образом их дождаться. В противном случае исключения будут игнорироваться, и код завершится до фактического завершения задач. Так что да, вам, вероятно, следует использовать policy.ExecuteAsync()
вместо этого. Это выглядело бы примерно так:
var tasks = myObjs
.Select(obj => Task.Factory.StartNew(() => obj.Do(), TaskCreationOptions.LongRunning))
.ToList();
// sometime later
await Task.WhenAll(tasks);
Комментарии:
1. Да, теперь это работает. Я использовал Task. WhenAll(задачи). GetAwaiter().GetResult(); в моем методе синхронизации и использовалась версия RetryAsync() политики.