2017-01-28 7 views
1

От https://msdn.microsoft.com/en-us/library/mt674882.aspx#Threads:Как асинхронно и ожидают замены существующих подходов?

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

Мне кажется, что цепочка из async функций должна в конечном итоге заканчиваться ожиданием чего-то случившегося, которое находится вне контроля вашей программы. Некоторая загрузка через Интернет или ввод пользователя или что-то в этом роде.

Как насчет ситуаций, когда ваша программа должна выполнять длительные вычисления? Это должно было бы быть в методе, который сам не использует await, потому что нечего ждать, когда он выполняет всю работу. Если await не используется, то управление не вернется обратно к вызывающей функции, правильно? Если это так, то, конечно, это даже не асинхронно.

Кажется BackgroundWorker хорошо подходит для длительных вычислений: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx#Examples

Есть ли способ использовать async/await для этой цели?

+1

Использование «BackgroundWorker» может быть преобразовано в несколько или одну «Задачу», а затем вы можете их ожидать. –

+0

Я начал писать ответ, но понял, что ответ будет слишком длинным и слишком широким для форума. Но вкратце: понятие асинхронного программирования может быть немного сложно понять. Во многих случаях можно использовать асинхронное программирование, но не все. GUI - прекрасный пример, когда асинхронное программирование работает очень хорошо. Шахматы, не так много. Я бы посоветовал вам прочитать дополнительную литературу по этой теме, чтобы получить более глубокое понимание. –

+1

async без ожидания на самом деле просто синхронно – Edward

ответ

2

Ключ здесь:

В сочетании с Task.Run, асинхронная программирование лучше BackgroundWorker для операций процессора переплета из-за асинхронное программирование разделяет детали координации ведения кода из работа , что Task.Run передается в threadpool.

Для CPU переплета работы (или IO переплет, это не имеет значения), Task.Run будет работать ваш код в отдельном потоке из пула потоков, поэтому текущий код может await, потому что он работает на другой поток. С точки зрения второй нити работа является синхронной, но с точки зрения первого потока работа асинхронна.

Вторая вещь - контекст координации. Я не использовал BackgroundWorker, но из моего понимания текста вам потребуется вручную проверить, завершена ли работа, а затем извлекать результаты или, возможно, распространять исключения и т. Д. В подходе async/await все это покрыто для вас.

В целом, кажется, что подход async/await является более дружественным для чтения способом делать вещи по сравнению с BackgroundWorker способом.

Edit:

Вы не можете использовать await на non-awaitable методов. Задача, связанная с ЦП, никогда не может быть действительно асинхронной, потому что что-то нужно вычислить, и для этого нужен поток. Либо текущий поток выполнит вычисление (блокирование), либо передаст его другому фоновому потоку, поэтому текущий поток не блокирует и не асинхронен.

Если вы знакомы с Node.js, вы заметите, что очень сложно обрабатывать задачи, связанные с CPU, и часто вам нужно будет реорганизовать ваш код.

Однако, как пользователь, ваш текущий поток является асинхронным независимо от того, является ли метод, который вы ожидаете, асинхронным или другим потоком.

+0

Итак, решение состоит в том, чтобы просто создать задачу нормально и ждать ее, а не только ждать задач, возвращаемых функциями 'async'? Здесь я думал об использовании 'async' без' await', но я должен был подумать об использовании 'await' без' async'. –

+0

Да, если вы хотите запустить какую-то задачу на заднем плане, просто используйте Task.Run. Использование asyc без ожидания эффективно делает его синхронным, и вы не можете использовать await без async, потому что ожидание - это контекстуальное ключевое слово, которое рассматривается как идентификатор, за исключением случаев, когда присутствует модификатор async. –

+0

Хорошо, что я имел в виду, когда я сказал 'await' без' async', это не то, что я бы использовал ключевое слово ожидания в не-асинхронной функции, но я ожидал чего-то, что само не было вызвано асинхронным функция. –

1

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

Да; чистый код async обычно используется с вводом/выводом или другими «событиями» (например, таймеры, уведомления или, реже, пользовательский ввод).

Как насчет ситуаций, когда ваша программа должна выполнять долгий расчет?

Это не основной вариант использования async. Тем не менее, это большой вариант использования для параллельных вычислений (Parallel/PLINQ), или если работа меньше, пул потоков (Task.Run).

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

Это верно; метод async без await будет работать синхронно. И на самом деле, если вы введете это в Visual Studio, компилятор даст вам предупреждение, которое на самом деле говорит: «Этот метод будет работать синхронно». Потому что большую часть времени это ошибка.

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

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

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

await Task.Run(() => Parallel.ForEach(...)); 

кажется BackgroundWorker хорошо подходит для длительных расчетов

Не совсем. Получение результатов немного неудобно, так как легко пропустить ошибки, и результаты не являются безопасными для типов. Кроме того, очень быстро скоординировать координацию нескольких BGW. У меня есть серия блога, которая shows how BackgroundWorker should essentially be considered obsoleted by Task.Run.

+2

@ Kyle - Stephen's [Нет нитки] (http://blog.stephencleary.com/2013/11/there-is-no-thread.html) post также хорошо читает это: «Мне кажется что цепочка асинхронных функций должна в конечном итоге заканчиваться ожиданием того, что что-то произойдет, что находится вне контроля вашей программы », так как важно понять преимущество, которое это дает для операций с привязкой к I/O. – sellotape

+0

Хм, когда я сказал, что BackgroundWorker хорошо подходит, я просто имел в виду, что документация заставляет задуматься, что это то, для чего был создан BackgroundWorker, в отличие от async/wait, который, по-видимому, не был разработан с учетом длительных вычислений. –