Распараллеливание задач с помощью polly

#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() политики.