Многопоточность: назначение ключевого слова async в вызове Task.Run

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

  1. await Task.Run(async () => Method());

  2. await Task.Run(() => Method());

Какова цель использования async в вызове Task.Run()?

Должен ли я быть await Task.Run(async () => await Method());?

Llama 17.12.2018 02:18

Если у вас случай 1, то @John верен, за исключением того, что его можно упростить до await Method()

Nathan Werry 17.12.2018 02:19

Предполагая, что Method возвращает задачу, 1 / не имеет преимущества перед 2 / и имеет небольшие накладные расходы из-за распределения конечного автомата.

Kevin Gosse 17.12.2018 08:36

@NathanWerry Не обязательно. Если метод блокирует поток на значительный период времени, прежде чем уступить, может быть законным запустить его в отдельном потоке (например, чтобы избежать блокировки пользовательского интерфейса).

Kevin Gosse 17.12.2018 08:38

@KevinGosse, я расширял то, что прокомментировал Джон, в котором у него есть функция, которая является асинхронной, так что да, это предположение было, но, вероятно, должно было быть упомянуто. Кроме того, он выполняется в отдельном потоке. Функция уже использует шаблон async / await, поэтому мы можем просто написать await вместо того, чтобы заключать асинхронную задачу в асинхронную задачу.

Nathan Werry 17.12.2018 14:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
121
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вызываемый вами метод является асинхронным, вы можете использовать async / await в функции.

async Task MainAsync()
{
   await Task.Run(async () => await MethodAsync());
   await Task.Run(() => Method());
}
async Task MethodAsync() { ... }
void Method() { ... }

В чем преимущество await Task.Run(async () => await MethodAsync()); перед await MethodAsync();?

Llama 17.12.2018 02:24

Как упоминалось в комментарии к вопросу, строка 3 является чрезмерным усложнением и может быть сокращена до await MethodAsync().

Nathan Werry 17.12.2018 02:24
Ответ принят как подходящий

Нет реальной причины использовать №1. Смысл использования Task.Run заключается в том, чтобы сделать длительную задачу или единицу работы с интенсивным вводом-выводом и сделать ее асинхронной, а поскольку №1 уже является асинхронным, асинхронная анонимная функция внутри Task.Run является избыточной и ненужной.

Либо вы выполните следующие действия, чтобы преобразовать единицу работы в асинхронную:

await Task.Run(() => Method());
public void Method() 
{ 
    //doing intensive work here
}

Или вы просто await - уже асинхронную единицу работы.

await MethodAsync();
public async Task MethodAsync()
{
    //doing async work here
}

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

ckuri 17.12.2018 08:37

Вы уверены, что? В документации по async есть несколько упоминаний о чтении и записи файлов. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…

Nathan Werry 17.12.2018 14:32

Да, чтение / запись файлов - это задача, связанная с вводом-выводом, которую не нужно заключать в Task.Run, о чем и была моя первая часть. Моя вторая часть была о некоторой гипотетической функции EncryptAsync(string fileName), которая возвращает задачу, поскольку использует асинхронные файловые функции. Однако в этом случае шифрование может быть дорогостоящим с вычислительной точки зрения, но все равно будет выполняться в вызывающем основном (UI) потоке, потому что функции асинхронного ввода-вывода часто не используют потоки для асинхронности. В этом случае имеет смысл заключить EncryptAsync в Task.Run, чтобы часть шифрования выполнялась в отдельном потоке.

ckuri 17.12.2018 19:45

Другие вопросы по теме