You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

std::async创建的线程未按预期并行执行耗时超预期的原因及解决方法

std::async创建的线程未按预期并行执行耗时超预期的原因及解决方法

嘿,我来帮你分析这个问题~先看看你的代码里的核心问题:

你的测试代码中,每个线程都频繁调用std::cout进行输出——比如进入线程时的日志、循环10次输出字符,还有最后的换行。而std::cout是线程安全但并非无锁实现的:多个线程同时操作cout时,底层会自动加锁避免输出乱码,但这会导致线程之间互相等待锁释放,产生额外的阻塞时间。你看到的2900ms比预期多出来的900ms,很大一部分就是这种锁竞争带来的开销。

另外还有个小细节:全局的gClock是程序启动时初始化的,而fnTestAsync里的begin是函数内的clock(),不过这对整体耗时的影响不大,核心问题还是cout的竞争。

接下来给你几个可行的解决办法:

解决方法1:减少cout调用次数(推荐)

让每个线程先把要输出的内容拼接成一个完整的字符串,然后一次性输出到cout,这样每个线程只触发一次cout的锁操作,大幅降低锁竞争的概率:

修改threadPool函数如下:

#include <sstream> // 需要包含这个头文件

char threadPool(char c) {
    std::ostringstream oss;
    // 把所有要输出的内容先写到内存流里
    oss << "enter thread :" << c << " cost time:" << clock() - gClock << "\n";
    for (int i = 0; i < 10; i++) {
        oss << c;
    }
    oss << "\n";
    
    // 一次性输出到cout
    std::cout << oss.str();
    
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return c;
}

这样修改后,每个线程只做一次cout输出,锁竞争的时间会大幅减少,整体耗时会非常接近你预期的2000ms。

解决方法2:关闭cout与C标准IO的同步

如果你的程序里没有混用C语言的printf、puts等IO函数,可以关闭cout和C标准IO的同步,减少底层的锁开销:

在main函数开头添加这两行代码:

std::ios_base::sync_with_stdio(false);
std::cout.tie(nullptr);

这个操作会让cout绕过C标准IO的同步机制,输出效率更高,也能减少部分锁竞争的开销。但要注意,如果同时使用C和C的IO函数,可能会出现输出顺序混乱的问题,所以只适合纯C IO的场景。

解决方法3:用互斥锁保护cout输出(适合需要有序输出的场景)

如果希望每个线程的输出内容不会互相穿插(比如完整看到一个线程的所有输出后再看另一个的),可以用std::mutex来保护cout的调用:

首先添加互斥锁的头文件并定义全局锁:

#include <mutex>
std::mutex cout_mutex;

然后修改threadPool里的输出部分:

char threadPool(char c) {
    // 保护第一个输出块
    {
        std::lock_guard<std::mutex> lock(cout_mutex);
        std::cout << "enter thread :" << c << " cost time:" << clock() - gClock << std::endl;
    }
    
    std::this_thread::sleep_for(std::chrono::seconds(2));
    
    // 保护循环输出和换行
    {
        std::lock_guard<std::mutex> lock(cout_mutex);
        for (int i = 0; i < 10; i++)
            std::cout << c;
        std::cout << std::endl;
    }
    return c;
}

这样每个输出块都会被互斥锁保护,输出不会乱序,但因为锁的存在,输出阶段还是会有串行的部分,不过比原代码的频繁锁竞争好很多,整体耗时也会更接近预期。

总结一下:核心问题就是多线程下频繁调用std::cout导致的锁竞争开销,通过减少cout调用次数、关闭同步或者加锁保护的方式都能解决,其中第一种方法(先缓存再一次性输出)效果最好,也最推荐。

备注:内容来源于stack exchange,提问作者YuHuanTin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 07:10:30