#c#
#c#
Вопрос:
Согласно Microsoft Visual C # Step by Step 9th edition:
Оператор await указывает, что метод должен быть запущен отдельной задачей, и вызывающий код приостанавливается до завершения вызова метода. Поток, используемый вызывающим кодом, освобождается и используется повторно. Это важно, если поток является потоком пользовательского интерфейса, поскольку это позволяет пользовательскому интерфейсу оставаться отзывчивым.
Предположим, у меня есть метод, который связан с вводом-выводом и освобождает процессор:
private async Task DoLongRunningIO()
{
...
}
Означает ли приведенный выше абзац, что запуск
await DoLongRunningIO();
message.Text = "Done";
в потоке пользовательского интерфейса будет по-прежнему поддерживаться адаптивный пользовательский интерфейс с момента выпуска потока пользовательского интерфейса? (в отличие от DoLongRunningIO().Wait()
, который заблокировал бы поток пользовательского интерфейса)
Если ответ «да», я предполагаю, что это было бы неверно, если бы длительно выполняемая задача была интенсивной для процессора, поскольку в этом случае поток пользовательского интерфейса все еще используется?
Комментарии:
1. Это не похоже на вопрос здесь. Это звучит как нечто, для чего вы можете легко настроить тесты и обнаружить сами.
2. @Enigmativity Я не согласен — это нелегко протестировать.
3. @EJoshuaS-Переустановить Monica — Почему бы и нет?
4. Поскольку я понимаю, что await планирует задачу в вызывающем потоке. Если вызывающим потоком был пользовательский интерфейс, по этой логике он приостановит поток пользовательского интерфейса, когда я действительно захочу проверить его отзывчивость. Мое понимание обсуждается. Возможно, мне придется настроить тест, чтобы выяснить это самому.
5. @youn — У вас, похоже, сложилось неправильное представление о
await
, и я думаю, что это ошибка книги.
Ответ №1:
Означает ли приведенный выше абзац, что запуск
await DoLongRunningIO(); message.Text = "Done";
в потоке пользовательского интерфейса будет по-прежнему поддерживаться адаптивный пользовательский интерфейс с момента выпуска потока пользовательского интерфейса?
ДА.
Если ответ «да», я предполагаю, что это было бы неверно, если бы длительно выполняемая задача была интенсивной для процессора, поскольку в этом случае поток пользовательского интерфейса все еще используется?
Нет, ваше предположение неверно. «Поток» и «процессор» — это не одно и то же. Даже если на вашем компьютере установлен только один процессор, может быть запущен один поток с интенсивным использованием процессора и поток пользовательского интерфейса, и ОС будет распределять процессор между ними. Вы можете обнаружить небольшое снижение скорости отклика, но поток пользовательского интерфейса все равно сможет выполняться.
Если у вас более одного ядра процессора, как в случае практически со всем современным оборудованием, то до тех пор, пока два потока не взаимодействуют, поток пользовательского интерфейса сможет работать беспрепятственно, даже если выполняется поток с интенсивным использованием процессора.
Обратите внимание, что все это предполагает, что DoLongRunningIO()
метод был написан правильно, т. Е. фактически отражает операцию, которая обрабатывается асинхронно. Для задачи, требующей больших затрат процессора, это обычно включает вызов Task.Run()
для выполнения операции, хотя, конечно, есть другие механизмы, которые можно использовать вместо этого.
Если этот метод написан неправильно, то все ставки отменяются. Вы не предоставили никаких подробностей об этом методе, поэтому невозможно сказать, так ли это в вашем сценарии.
В сторону:
Как бы то ни было, я не согласен с формулировкой «Оператор await указывает, что метод должен выполняться отдельной задачей», которую вы процитировали из книги. await
Оператор ничего не говорит о том, как следует запускать / вызывать / выполнять метод или операцию / и т.д. Единственное, что await
делает, это указывает точку в текущем методе, где, учитывая ожидаемый объект (обычно Task
), метод должен вернуться вызывающему, если объект не находится в завершенном состоянии. Любое выражение, генерирующее ожидаемый объект, должно обрабатывать, как создается эта задача и выполняется ли она в отдельном потоке или иным асинхронным образом.
Комментарии:
1. Я думал, что ключевое слово await специально планирует задачу в потоке вызывающего метода (т. Е. оно не порождает новый поток). Отсюда мой комментарий о том, что поток пользовательского интерфейса используется. Из той же главы книги: Когда компилятор C # сталкивается с оператором await в асинхронном методе, он эффективно переформатирует операнд, следующий за этим оператором, в задачу, которая выполняется в том же потоке, что и асинхронный метод.
2. «Я думал, что ключевое слово await специально планирует задачу в потоке вызывающего метода» — нет, это совершенно неправильное понимание
await
оператора. Смотрите мою правку выше;await
оператор не имеет ничего общего с планированием ожидаемой работы. Он только управляет механизмом, с помощью которого текущий метод имеет дело с ожиданием этой ожидаемой работы (т. Е., в частности, путем настройки сгенерированного компилятором конечного автомата таким образом, чтобы метод мог быть возобновлен в соответствующем месте, а затем возвращен вызывающему).3. Мне действительно не нравится книга, которую вы цитируете. Если там действительно написано «это эффективно переформатирует операнд, который следует за этим оператором, как задачу, которая выполняется в том же потоке, что и асинхронный метод» , то это не та книга, которую следует использовать.
await
Оператор ничего не «переформатирует», и это, конечно, не влияет на то, где выполняется операнд оператора (т. Е. ожидаемое выражение). Это может повлиять на то, где выполняется код в методе, следующий за инструкцией, содержащейawait
, например, позволяя методу возвращаться к исходному потоку, как в потоке пользовательского интерфейса.4. «Вы хотите сказать, что C # может запланировать ожидаемую задачу в другом потоке?» — Я говорю, что ожидание задачи не имеет ничего общего с тем, где эта задача запланирована. К тому времени, когда код начинает ожидать его, планирование уже выполнено. Ожидание совершенно не имеет отношения к планированию.
5. Ожидание не имеет ничего общего с планированием задач. То, как она будет запланирована, зависит от самой задачи. Await просто указывает, как эта функция будет возобновлена после завершения задачи.