Async Await и Task.Run проблема - PullRequest
0 голосов
/ 02 ноября 2018

Мне нужно знать, есть ли различия в этих записях, и если да, то каковы они? Это довольно сложно для меня:

1) Task.Run(async () => { await CheckVerification(); });
2) Task.Run(() => CheckVerification());
3) await Task.Run(async () => { await CheckVerification(); });

Ответы [ 2 ]

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

Может быть, легче понять разницу, если мы забудем о Task.Run на секунду. Разница между вашими 1-м и 2-м баллами в основном такая же, как ожидание или просто возвращение внутренней задачи из Task метода возврата:

// 1)
public async Task WithAwait() => await SomeOtherTaskReturningMethod();

// 2)
public Task WithoutAwait() => return SomeOtherTaskReturningMethod();

Первый создает другую задачу, которая оборачивает внутреннюю задачу, что является небольшим накладным расходом, но в остальном эти два метода функционально почти идентичны. Небольшая разница в том, что когда SomeOtherTaskReturningMethod выдает исключение, то внутренняя задача AggregatedException будет развернута, и (первое) внутреннее исключение будет выдано дальше. Конечно, все еще зависит от того, что происходит с внешней задачей. В вашем третьем пункте также ожидается, что вы получите развернутое исключение из внешнего задания (если оно есть), в то время как 1-й и 2-й примеры просто запущены и забыты.

Теперь давайте снова рассмотрим Task.Run. Главный вопрос, почему этот метод имеет перегрузки, которые принимают Task с (фактически Task возвращающие обратные вызовы), когда вы также можете просто вызвать await CheckVerification(); и получить тот же результат? (Я знаю, что это не было частью вопроса, но, возможно, стоит уточнить это)

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

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

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

TL; DR:

Так что я думаю, что реальный вопрос заключается в том,

await CheckVerification();

или

await Task.Run(() => CheckVerification());

- лучшее решение (или, может быть, одно из них без await, которое является режимом огня и забывания). В большинстве случаев я бы проголосовал за первый, но если вы действительно уверены, что задача, возвращаемая CheckVerification, должна быть назначена потоку пула (независимо от того, делает ли он это внутри или нет), тогда второй вариант также может быть оправдан .

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

1) Запускает задачу. Эта задача будет ожидать метода внутри, но асинхронно, поэтому ваш пользовательский интерфейс или вызывающий поток не будут блокироваться.

2) Запускает задачу, которая запускает другую задачу. Все работает асинхронно, ничего не ждет, полностью увольняйся и забудь.

3) Запустит задачу, эта задача запускает метод и ожидает его, возвращая контекст выполнения, позволяя вызывающему потоку отдавать контекст выполнения с его ожиданием, позволяя методу, вызывающему это, продолжить выполнение, пока не дойдет до ожидания этого способ.

...