Использование Async / Await внутри вложенного LINQ-Select без использования Task.WhenAll - PullRequest
0 голосов
/ 02 января 2019

Я пытаюсь дождаться асинхронной операции внутри оператора выбора, который находится внутри другого оператора выбора.

var result = someList
    .Select(table => new Table
    {
        Columns = table.Select(async column => new Column
        {
            Constraints = await GetColumnConstraints()
        })
    })
    .ToList();

Проблема в том, что вложенный оператор select возвращает список задач. Обычно мы будем использовать Task.WhenAll() для ожидания всех задач. Поэтому проще всего было бы изменить тип столбцов с List<Column> на List<Task<Column>>, а затем с помощью SelectMany() выбрать каждую задачу и дождаться ее. Но я не могу изменить тип столбцов.

Как мне достичь этого? Я не мог найти решение, которое не включает Task.WhenAll()

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Вам не нужно менять тип Column, вам просто нужно await результаты за пределами инициализатора для вашей таблицы.Это позволяет вам собрать результаты в columnTasks, await во всех них, а затем создать новую таблицу.

var result = someList.Select(async table =>
{
    var columnTasks = table.Select(async column => new Column()
    {
        Constraints = await GetColumnConstraints()
    });
    var columns = await Task.WhenAll(columnTasks);
    return new Table()
    {
        Columns = columns
    };
});

Обратите внимание, что async продвигается вверх по цепочке, поэтому reusltсейчас IEnumerable<Task<Table>> и вам нужно await Task.WhenAll, чтобы получить окончательную коллекцию Table

var tables = await Task.WhenAll(result);
0 голосов
/ 02 января 2019

Очевидно, Somelist - это последовательность Tables, где каждый Table имеет последовательность Columns.

Мне кажется, что столбцы этих таблиц не влияют на GetColumnConstraints().Почему вы вызываете эту функцию один раз для каждого столбца?Разве не было бы эффективнее, если бы вы вызывали его только один раз?

var columnConstraints = await GetColumnConstraintsAsync();
var result = tables.Select(table => new Table
{
    Columns = table.Select(column => new Column
    {
        Constraints = columnConstraints,
        ...
    })
})
.ToList();

Возможно, вы упростили задачу и перечислимая таблица и столбец влияют на извлекаемые ограничения, например, потому что онииспользуются в качестве входных переменных.Может быть, если вы вызываете функцию во второй раз, вы получаете различные ограничения?

Если вам действительно нужно получить ограничения для столбца на таблицу, то сначала дождитесь получения ограничений перед созданием таблицы:

var result = tables.Select(table => 
{
    var columnTasks = table.Select(column => GetColumnContraintsAsync(...)).ToArray();
    // all tasks are running now, wait until all are completed:
    await Task.WhenAll(columnTasks);
    // fetch the result from every task:
    var columnTaskResults = columnTasks.Select(columnTask => columnTask.Result).ToList();

    // create a Table with these results and return it:
    return new Table
    {
        Columns = columnTaskResults,
    };
})
.ToList();
...