2016-10-19 3 views
0

Я пытался выяснить, почему пользовательский интерфейс блокирует метод ViewModel, и понял, что эта часть код:Разница между Task.WhenAll (Task.Run (метод async)) и Task.WhenAll (метод async)

await Task.WhenAll(getOutput1(), getOutput2()); 

была проблема. Мне удалось разблокировать пользовательский интерфейс с помощью:

await Task.WhenAll(Task.Run(() => getOutput1()), Task.Run(() => getOutput2())); 

getOutput1() и getOutput2() оба async с Task возвращаемых типов в ViewModel, а код вызывается из вида.

В чем разница с вызовом Task.WhenAll, когда я вызываю Task.Run() и непосредственно передаю задачу?

+1

Если 'getOutput1' и' getOutput2' оба «действительно» асинхронны, тогда первый параметр должен работать правильно. можете ли вы показать эти методы? Обратите внимание, что метод async будет выполняться синхронно, если вы не читаете операции «IO». – Fabio

+5

Весьце зависит от характера 'getOutput1' и' getOutput2'. Если они выполняют значительную работу без использования какого-либо асинхронного поведения, эта работа выполняется в исходном потоке в версии 1 вашего кода. –

+0

@Damien_The_Unbeliever на самом деле вы правы, я только вызываю асинхронное поведение, когда планирую на поток пользовательского интерфейса внутри метода. Спасибо за понимание – Tyress

ответ

2

В чем разница с вызовом Task.WhenAll, когда я вызываю Task.Run() и непосредственно передаю задачу?

Вызов методов напрямую вызовет их в потоке пользовательского интерфейса. Вызов их изнутри Task.Run вызовет их в потоке пула потоков.

Вывод: getOutput1 и/или getOutput2 на самом деле не асинхронны. (Возможно, что метод возвратит Task - и таким образом появится асинхронный - но на самом деле просто блокировать синхронно).

2

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

Однако, если методы также задействованы в длительной работе с привязкой к ЦПУ, поток пользовательского интерфейса не будет заблокирован во время выполнения операции асинхронного ввода-вывода, но будет выполняться при работе с ЦП.

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

Другой вариант вместо использования Task.Run из ViewModel заключается в использовании ConfigureAwait(false), ожидая операций async ввода-вывода в ваших методах, делая это будет информировать остальную часть метода после части ожидания, что он не нуждается в исходный контекст, который он имел (что, вероятно, является интерфейсом пользователя), и что остальная часть метода также может быть выполнена в другом потоке ThreadPool.

Для получения дополнительной информации об асинхронных и ожидающих методах см. Вопрос this, который объединяет операции ввода-вывода и работы с ЦП.

Смежные вопросы