В чем проблема с std::async?
В начале этого клипа из C++ And Beyond я что-то слышал о проблемах с std::async
, У меня есть два вопроса:
Для младшего разработчика, есть ли набор правил, что делать и чего избегать при использовании
std::async
?Какие проблемы представлены в этом видео? Они связаны с этой статьей?
2 ответа
Есть несколько вопросов:
std::async
без политики запуска позволяет библиотеке времени выполнения выбирать, запускать ли новый поток или запускать задачу в потоке, который вызвалget()
или жеwait()
на будущее. Как говорит Херб, это тот случай, который вы, скорее всего, захотите использовать. Проблема в том, что это оставляет его открытым для QoI библиотеки времени выполнения, чтобы правильно определить количество потоков, и вы не знаете, будет ли задача иметь поток для себя, поэтому использование локальных переменных потока может быть проблематичным. Это то, что беспокоит Скотта, насколько я понимаю.Используя политику
std::launch::deferred
на самом деле не запускает задачу, пока вы явно не позвонитеget()
или жеwait()
, Это почти никогда не то, что вы хотите, так что не делайте этого.Используя политику
std::launch::async
начинает новую тему Если вы не отслеживаете количество потоков, это может привести к слишком большому числу запущенных потоков.Херб обеспокоен поведением
std::future
деструктор, который должен ждать завершения задачи, хотя MSVC2012 имеет ошибку в том, что он не ждет.
Для младшего разработчика я бы предложил:
- использование
std::async
с политикой запуска по умолчанию. - Убедитесь, что вы явно ждете все свое будущее.
- Не используйте локальное хранилище в асинхронных задачах.
Я не мог не согласиться с советами использовать политику по умолчанию.
Если вы испытываете трудности при разработке независимых вычислительных блоков, вы, вероятно, не ожидаете, что они будут работать последовательно, в то время как полдюжины процессоров крутят свои пальцы, что может "законно" произойти в зависимости от выбранного вами компилятора.
Неявное предположение о поведении по умолчанию заключается в том, что какой-то сложный механизм пула потоков оптимизирует размещение задач (возможно, позволяя некоторым из них запускаться последовательно на ЦП вызывающего), но это чистая фантазия, поскольку ничто не указывает, что должна делать среда выполнения C++ (что может быть в любом случае выходит за рамки компиляции).
Для меня это больше похоже на неопределенное поведение.
Класс с именем "async" должен запускать асинхронные исполнительные блоки, если какой-либо явный и детерминированный параметр поведения не говорит об обратном.
Честно говоря, за исключением цели отладки, я не вижу смысла в launch::deferred
Если вы не планируете писать свой собственный псевдо-планировщик, в этом случае вам будет лучше использовать простые потоки.
Так что мой совет будет уточнить launch::async
когда вы используете async
, (говоря компилятору что-то вроде "эй, я хочу асинхронную задачу, но действительно асинхронно, хорошо?") и не использовать async
на всех, если вы просто хотите выполнять задачи последовательно.
Если у вас возникли проблемы с асинхронными задачами, может быть удобно вернуться к deferred
политика их отладки проще, но это все.