В чем разница между std::async и std::thread в C++?

Ответ

std::thread — это низкоуровневый примитив для создания и управления потоком. Он требует явного управления жизненным циклом потока (вызов join() или detach()).

std::async — это высокоуровневая абстракция для запуска асинхронных задач. Она возвращает std::future<T> и делегирует управление потоками стандартной библиотеке (используя внутренний пул потоков или создавая новый).

Ключевые различия:

  1. Управление потоком:

    • std::thread создает поток немедленно.
    • std::async может отложить выполнение (ленивая политика std::launch::deferred) или запустить асинхронно (std::launch::async).
  2. Возврат результата и обработка ошибок:

    • std::thread не предоставляет прямого способа получить результат работы функции. Для передачи данных или ошибок нужны дополнительные механизмы (например, общие переменные с синхронизацией).
    • std::async инкапсулирует результат (или исключение) в объект std::future. Исключение, выброшенное в асинхронной задаче, будет перевыброшено при вызове future.get().
  3. Производительность и ресурсы:

    • Создание std::thread — относительно дорогая операция.
    • std::async может использовать существующие потоки из внутреннего пула, что эффективнее для множества мелких задач.

Пример:

// Пример с std::thread (нужно вручную передать результат)
int result;
std::thread t([&result]() { result = someHeavyCalculation(); });
t.join();
std::cout << result << std::endl;

// Пример с std::async (результат инкапсулирован)
auto future = std::async(std::launch::async, []() {
    return someHeavyCalculation();
});
// ... делаем другую работу ...
std::cout << future.get() << std::endl; // Блокируется, пока результат не готов

Когда что использовать:

  • std::thread — когда нужен полный низкоуровневый контроль над потоком (например, привязка к конкретному ядру CPU, нестандартный стек).
  • std::async — для большинства задач «запусти-и-забудь» с получением результата, так как это безопаснее и часто эффективнее.

Ответ 18+ 🔞

Ёпта, ну смотри, тут история про потоки, как будто на дворе 2002-й год и мы только про concurrency узнали. Есть два чувака: std::thread и std::async. Первый — это как голый провод под напряжением, брать голыми руками — овердохуища мороки. Второй — как розетка с защитой от детей, вставил вилку и похуй.

std::thread — это низкоуровневый примитив, типа кувалды. Сам создал поток, сам им управляй, сам не забудь его либо прибить (join()), либо отпустить в свободное плавание (detach()), а то будет тебе хиросима и нигерсраки — программа упадёт, а ты будешь охуевать, почему.

std::async — это уже обёртка, интеллигент такой. Ты говоришь: «Эй, выполни эту хуйню асинхронно», а он тебе в ответ кидает std::future<T> — типа расписку, что результат будет. А сам уже решает, создавать новый поток или взять из какого-то внутреннего пула, тебе, в общем, доверия ебать ноль, но зато удобно.

В чём разница, если по-простому:

  1. Кто рулит: С std::thread ты сам, как заправский механик, крутишь гайки. С std::async ты как пассажир в такси — сказал адрес и ждёшь, пока довезут, можешь по дороге спать.
  2. Где результат: В std::thread результат сам выкручивайся, как хочешь — через общие переменные, мьютексы, ещё какую мудню. В std::async всё аккуратненько упаковано в этот future. Вызвал get() — и тебе вывалили результат. А если там в потоке исключение вылетело — так оно тебе прямо в get() и прилетит, не потеряется, ебать копать.
  3. Сколько стоит: Создать новый std::thread — это не хуй собачий, операция тяжёлая. std::async может переиспользовать уже созданные потоки, что для кучи мелких задач — просто пизда рулю.

Смотри, как это выглядит в коде:

// Вот так с std::thread — старый добрый геморрой.
int result; // Общая переменная, волнение ебать.
std::thread t([&result]() { result = someHeavyCalculation(); }); // Запустили.
t.join(); // Обязательно ждём, а то поток убежит, а мы с пустым result останемся.
std::cout << result << std::endl;

// А вот так с std::async — цивилизация, блядь.
auto future = std::async(std::launch::async, []() {
    return someHeavyCalculation(); // Просто возвращаем значение.
});
// ... а тут мы пока можем делать другую работу, пить кофе...
std::cout << future.get() << std::endl; // Достаём результат, когда надо.

Так когда что брать?

  • std::thread — когда ты реально знаешь, что делаешь, и тебе нужен тотальный контроль. Типа настроить размер стека или привязать поток к конкретному ядру процессора. Это для гиков, которые не бздят.
  • std::async — для 95% всех остальных случаев. Запустил задачу, получил future, и живи спокойно. Безопаснее, проще, и часто ещё и быстрее выходит. Чувак, если сомневаешься — бери async, не прогадаешь.