Почему WaitAll не работает должным образом

167
18 апреля 2022, 19:40
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
    _timer.Stop();
    _logic.AddLogToMainFileServerLogs("*********Метод распределения запущен из таймера.*********");
    List<Task> tasks = new List<Task>();
    foreach (var depot in _logic.Depots)
    {
        _logic.AddLogToMainFileServerLogs("*********РЦ " + depot.Code + " запущено в поток.*********");
        Task task = Task.Run(() => _logic.DistributeTrucks(depot.Code));
        tasks.Add(task);
        //_= await _logic.DistributeTrucks(depot.Code);
    }
    Task.WaitAll(tasks.ToArray());
    _logic.AddLogToMainFileServerLogs("*********Метод распределения из таймера отработал РЦ.*********");
    _timer.Start();
}  

Я хочу что бы метод DistributeTrucks выполнялся параллельно, но при этом запуск таймера должен происходить только тогда, когда все задачи выполняться. Сейчас я вижу в логах следующее:

  1. Метод распределения запущен из таймера.
  2. РЦ 1 запущено в поток.
  3. РЦ 2 запущено в поток.
  4. РЦ 3 запущено в поток.
  5. Метод распределения из таймера отработал РЦ.
  6. Выполнения методов

А хочу видеть:

  1. Метод распределения запущен из таймера.
  2. РЦ 1 запущено в поток.
  3. РЦ 2 запущено в поток.
  4. РЦ 3 запущено в поток.
  5. Выполнение методов
  6. Метод распределения из таймера отработал РЦ.

Что не так делаю?

 public async void DistributeTrucks(string depotCode)
Answer 1

async void технтчески невозможно ожидать, но возможно async Task.

public async Task DistributeTrucks(string depotCode)

Тогда строчку с таской можно поменять вот так

Task task = _logic.DistributeTrucks(depot.Code);

Еще подскажите, в данном случае, метод DistributeTrucks будет работать параллельно, правильно?

Технически это работает так: когда в внутри метода встречается первый await, асинхронная машина состояний позвращает ожидающий завершения метода Task в точку вызова. Код, размещенный до первого await будет выполнен синхронно как в самом обычном синхронном метода (уделяйте этому внииание при написании асинхронных методов, иначе можете ропасть в ситуацию, когда асинхронный метод блокирует вызывающий поток на некоторое время). То есть в этот момент переменная task будет добавлена в список и цикл продолжит выполение.

Следовательно одновременно может выполняться (ожидаться) несколько или даже много асинхронных ожиданий. Можно сказать, что это параллельно, да. Но технически это не так. Вы просто ожидаете список тасок WaitAll, которые внутри себя тоже что-то ждут, ну там где у вас await внутри метода DistributeTrucks, при ожидании код не выполняется, этим и отличается асинхронность от параллельности. По сути, можно выполнять одновременно кучу асинхронных вызовов, технически используя для выполнения кода всего один поток. А когда есть всего один поток, то о какой параллельности может быть речь, верно?

Говоря самым простым языком Thread поток - это выполнялка, а Task - это ожидалка. При том, ожидалка может ждать и завершения выполнения кода в отдельном потоке текущего приложения await Task.Run, и выполнения какой-то операции вне текущего компьютера, например ожидать ответа из сети await httpClient.GetStringAsync(). Во втором случае код выполняется на сервере, а вы просто ждете результат.

READ ALSO
Цифровой сертификат и расширения

Цифровой сертификат и расширения

Всем доброго времени суток!

156
Не удается закрыть Excel в диспетчере задач

Не удается закрыть Excel в диспетчере задач

После создания объекта Excel не удается его закрыть: он также висит диспетчере задач:

168
Приведение строки к маске ввода

Приведение строки к маске ввода

От пользователя приходит некий код, и он сравнивается с форматом кода для каждой конкретной страны(он может быть разным), и если его можно...

168
Не заполняется DataGrid

Не заполняется DataGrid

Пишу на WPFВот мой код:

210