首页 > 解决方案 > 使用 stringstreams 加速 std::cout 日志记录

问题描述

我正在尝试加快一个多线程程序的速度,该程序可以打印很多std::cout. 打印的大部分内容都是由多个变量(字符串、数字等)拼凑而成的字符串。访问std::cout受互斥体保护,以防止来自多个线程的打印输出以以下方式混合:

{
    std::lock_guard<std::mutex> lock(mutex);
    std::cout << stringA << " 1 " << 5  << 'C' << std::endl;
}

测量结果表明,多个线程花费大量时间等待互斥体,std::cout而对于大而复杂的字符串似乎需要一些时间。

我现在的问题是:

理论上我可以通过std::stringstream在进入互斥锁之前将字符串组装成 a 来减少锁争用,然后将已经组装的字符串发送到std::cout吗?如:

{
    std::stringstream ss;
    ss << stringA << " 1 " << 5  << 'C' << std::endl;
    std::lock_guard<std::mutex> lock(mutex);
    std::cout << ss.str();
}

如果是,是否可以进一步改进?

标签: c++

解决方案


理论上我可以通过在进入互斥体之前将字符串组装成 std​​::stringstream 来减少锁争用,然后将已经组装的字符串发送到 std::cout 吗?

绝对地。operator<<必须做一些工作来格式化传入的类型。将字符串组装成 astd::stringstream意味着您预先完成所有工作,只需将组装好的字符串写出到std::cout,这意味着您在锁定下花费的时间更少。

但是,请注意,它会按值ss.str()返回std::string。这意味着您正在复制关键区域内的字符串。最好直接std::cout << ss.rdbuf()在里面写下底层字符串std::stringstream

除此之外,您还需要尽可能减少输出所花费的时间std::cout。如果你从不调用任何 C stdio 函数,你应该调用std::ios_base::sync_with_stdio(false)

把它放在一起:

// Near the beginning of your program:
std::ios_base::sync_with_stdio(false);

// ...

{
    // Prefer using ostringstream if you never need to read from it
    std::ostringstream ss;
    // std::endl is never needed. Use '\n' instead. If you want to flush,
    // explicitly write `ss << '\n' << std::flush`. For stringstreams, I believe
    // it doesn't matter, but it's good to get into the habit of doing this
    ss << stringA << " 1 " << 5  << 'C' << '\n';
    std::lock_guard<std::mutex> lock(mutex);
    std::cout << ss.rdbuf();
}

推荐阅读