используйте Task.Run () внутри метода Select LINQ - PullRequest
0 голосов
/ 27 ноября 2018

Предположим, у меня есть следующий код (только для изучения):

static async Task Main(string[] args)
{
    var results = new ConcurrentDictionary<string, int>();

    var tasks = Enumerable.Range(0, 100).Select(async index =>
    {
        var res = await DoAsyncJob(index);
        results.TryAdd(index.ToString(), res);
    });

    await Task.WhenAll(tasks);

    Console.WriteLine($"Items in dictionary {results.Count}");
}

static async Task<int> DoAsyncJob(int i)
{
    // simulate some I/O bound operation
    await Task.Delay(100);

    return i * 10;
}

Я хочу знать, в чем будет разница, если я сделаю это следующим образом:

var tasks = Enumerable.Range(0, 100)
    .Select(index => Task.Run(async () =>
    {
        var res = await DoAsyncJob(index);
        results.TryAdd(index.ToString(), res);
    }));

Я получаю одинаковые результаты в обоих случаях.Но код выполняется аналогично?

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Task.Run для выполнения связанных с ЦП синхронных операций в потоке пула потоков.Поскольку эта операция, которую вы выполняете, уже асинхронна, поэтому использование Task.Run означает, что вы планируете работу для выполнения в потоке пула потоков, и эта работа просто запускает асинхронную операцию, которая затемзавершается почти сразу и выполняет любую асинхронную работу без блокировки потока пула потоков.Таким образом, с помощью Task.Run вы ожидаете, чтобы запланировать работу в пуле потоков, но на самом деле не выполняете значимой работы.Вам лучше просто запустить асинхронную операцию в текущем потоке.

Единственное исключение было бы, если бы DoAsyncJob были реализованы неправильно и по какой-то причине не были фактически асинхронными, вопреки его имени и подписи, и фактически выполнили много синхронной работы перед возвратом.Но если он делает это, вы должны просто исправить этот ошибочный метод, а не использовать Task.Run для его вызова.

На заметку о том, что нет никакой причины иметь ConcurrentDictionary для сбора результатов здесь,Task.WhenAll возвращает коллекцию результатов всех выполненных вами задач.Просто используйте это.Теперь вам даже не нужен метод, чтобы обернуть ваш асинхронный метод и обработать результат каким-либо особым образом, дополнительно упрощая код:

var tasks = Enumerable.Range(0, 100).Select(DoAsyncJob);

var results = await Task.WhenAll(tasks);

Console.WriteLine($"Items in results {results.Count}");
0 голосов
/ 27 ноября 2018

Да, оба случая выполняются одинаково.На самом деле они выполняются точно так же.

...