Это слабо связано с этим вопросом: объединены ли std :: thread в С++ 11? , Хотя вопрос отличается, намерение то же самое:
Вопрос 1. Имеет ли смысл использовать собственные (или сторонние библиотеки) пулы потоков, чтобы избежать дорогостоящего создания потоков?
В другом вопросе был сделан вывод, что вы не можете полагаться на std::thread
для объединения (это может быть или не быть). Однако std::async(launch::async)
видимому, имеет гораздо больше шансов быть объединенным.
Не думаю, что это навязывается стандартом, но IMHO, я ожидаю, что все хорошие реализации С++ 11 будут использовать пул потоков, если создание потоков будет медленным. Я предполагаю, что только на платформах, где создание нового потока недорого, они всегда создают новый поток.
Вопрос 2: Это именно то, что я думаю, но у меня нет фактов, чтобы это доказать. Я вполне могу ошибаться. Это обоснованное предположение?
Наконец, здесь я предоставил некоторый пример кода, который сначала показывает, как я думаю, что создание потока может быть выражено async(launch::async)
:
Пример 1:
thread t([]{ f(); });
// ...
t.join();
становится
auto future = async(launch::async, []{ f(); });
// ...
future.wait();
Пример 2: запустить и забыть нить
thread([]{ f(); }).detach();
становится
// a bit clumsy...
auto dummy = async(launch::async, []{ f(); });
// ... but I hope soon it can be simplified to
async(launch::async, []{ f(); });
Вопрос 3: Вы бы предпочли async
версии версиям thread
?
Остальное больше не является частью вопроса, но только для уточнения:
Почему возвращаемое значение должно быть присвоено фиктивной переменной?
К сожалению, текущий стандарт С++ 11 требует, чтобы вы захватили возвращаемое значение std::async
, так как в противном случае выполняется деструктор, который блокируется до завершения действия. Это считается ошибкой в стандарте (например, Хербом Саттером).
Этот пример cppreference.com прекрасно иллюстрирует это:
{
std::async(std::launch::async, []{ f(); });
std::async(std::launch::async, []{ g(); }); // does not run until f() completes
}
Еще одно уточнение:
Я знаю, что у пулов потоков могут быть другие законные применения, но в этом вопросе меня интересует только то, как избежать дорогостоящих затрат на создание потоков.
Я думаю, что все еще существуют ситуации, когда пулы потоков очень полезны, особенно если вам нужен больший контроль над ресурсами. Например, сервер может решить обрабатывать только фиксированное количество запросов одновременно, чтобы гарантировать быстрое время отклика и повысить предсказуемость использования памяти. Пулы потоков должны быть в порядке, здесь.
Локальные переменные потока также могут быть аргументом для ваших собственных пулов потоков, но я не уверен, насколько это актуально на практике:
- Создание нового потока с помощью
std::thread
начинается без инициализированных локальных переменных потока. Может быть, это не то, что вы хотите. - В потоках, порожденных
async
, мне несколько непонятно, потому что поток мог быть использован повторно. Насколько я понимаю, локальные переменные потока не гарантированно сбрасываются, но я могу ошибаться. - Использование собственных пулов потоков фиксированного размера, с другой стороны, дает вам полный контроль, если вам это действительно нужно.