Как реализовать эффективный WhenEach, который передает IAsyncEnumerable результатов задачи?C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как реализовать эффективный WhenEach, который передает IAsyncEnumerable результатов задачи?

Сообщение Anonymous »

Я пытаюсь обновить свой набор инструментов новыми инструментами, предлагаемыми C# 8, и один метод, который кажется особенно полезным, — это версия Task.WhenAll, которая возвращает IAsyncEnumerable. Этот метод должен передавать результаты задачи в потоковом режиме, как только они станут доступны, поэтому называть его WhenAll не имеет особого смысла. WhenEach звучит более уместно. Сигнатура метода:

Код: Выделить всё

public static IAsyncEnumerable WhenEach(Task[] tasks);
Этот метод можно использовать следующим образом:

Код: Выделить всё

var tasks = new Task[]
{
ProcessAsync(1, 300),
ProcessAsync(2, 500),
ProcessAsync(3, 400),
ProcessAsync(4, 200),
ProcessAsync(5, 100),
};

await foreach (int result in WhenEach(tasks))
{
Console.WriteLine($"Processed: {result}");
}

static async Task ProcessAsync(int result, int delay)
{
await Task.Delay(delay);
return result;
}
Ожидаемый результат:

Обработано: 5

Обработано: 4

Обработано: 1

Обработано: 3

Обработано: 2

Мне удалось написать базовую реализацию с использованием метода Task.WhenAny в цикле, но с этим подходом есть проблема:

Код: Выделить всё

public static async IAsyncEnumerable WhenEach(
Task[] tasks)
{
var hashSet = new HashSet(tasks);
while (hashSet.Count > 0)
{
var task = await Task.WhenAny(hashSet).ConfigureAwait(false);
yield return await task.ConfigureAwait(false);
hashSet.Remove(task);
}
}
Проблема в производительности. Метод Task.WhenAny должен следить за завершением всех поставленных задач, и он делает это путем присоединения и отсоединения продолжений, поэтому его повторный вызов в цикле приводит к вычислительной сложности O(n²). Моя наивная реализация с трудом справляется с обработкой 10 000 задач. На моей машине накладные расходы составляют почти 10 секунд. Мне бы хотелось, чтобы этот метод был почти таким же производительным, как встроенный Task.WhenAll, который мог бы легко обрабатывать сотни тысяч задач. Как я могу улучшить метод WhenEach, чтобы он работал достойно?

Подробнее здесь: https://stackoverflow.com/questions/581 ... le-of-task
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Как реализовать эффективный WhenEach, который передает IAsyncEnumerable результатов задачи?
    Гость » » в форуме C#
    0 Ответы
    26 Просмотры
    Последнее сообщение Гость
  • Итерация IAsyncenumerable в функции, возвращающей IAsyncenumerable с отменой
    Anonymous » » в форуме C#
    0 Ответы
    26 Просмотры
    Последнее сообщение Anonymous
  • Как дождаться всех результатов от IAsyncEnumerable<>?
    Anonymous » » в форуме C#
    0 Ответы
    21 Просмотры
    Последнее сообщение Anonymous
  • Получение 2 -го `iAsyncenumerator <>` из того же `jasyncenumerable <>` на основе `task.wheneach <>` method
    Anonymous » » в форуме C#
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous
  • Получение 2 -го `iAsyncenumerator <>` из того же `jasyncenumerable <>` на основе `task.wheneach <>` method
    Anonymous » » в форуме C#
    0 Ответы
    15 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C#»