c++ - 为什么这种使用 putchar_unlocked 的方法打印字符串比 printf 和 cout 慢?

标签 c++ c printf cout putchar

我正在研究加速我的编程竞赛算法的方式,使用输入和输出处理的加速作为基础。

我目前正在使用线程不安全的 putchar_unlocked 函数在某些评估中进行打印。由于其线程不安全的特性,如果实现得当,我认为对于某些数据类型,此函数比 cout e printf 更快。​​

我实现了一个以这种方式打印字符串的函数(恕我直言,非常简单):

void write_str(char s[], int n){
    int i;
    for(i=0;i<n;i++)
        putchar_unlocked(s[i]);
}

我测试了一个大小为 n 且正好是 n 个字符的字符串。
但它是三者中最慢的,正如我们在这张输出写入次数与时间(以秒为单位)的图表中所见: Graph

为什么它是最慢的?

最佳答案

假设最多约 1,000,000 百万个字符的时间测量值低于测量阈值并且写入 std::coutstdout 是使用使用批量的形式进行的-写入(例如 std::cout.write(str, size)),我猜想 putchar_unlock() 大部分时间实际上都在更新数据结构除了放字符。其他批量写入会将数据批量复制到缓冲区中(例如,使用 memcpy())并仅在内部更新一次数据结构。

也就是说,代码看起来像这样(这是 pidgeon 代码,即,只是粗略地显示正在发生的事情;真正的代码至少会稍微复杂一些):

int putchar_unlocked(int c) {
    *stdout->put_pointer++ = c;
    if (stdout->put_pointer != stdout->buffer_end) {
        return c;
    }
    int rc = write(stdout->fd, stdout->buffer_begin, stdout->put_pointer - stdout->buffer_begin);
    // ignore partial writes
    stdout->put_pointer = stdout->buffer_begin;
    return rc == stdout->buffer_size? c: EOF;
}

代码的批量版本正在做一些类似的事情(使用 C++ 符号,因为它更容易成为 C++ 开发人员;同样,这是 pidgeon 代码):

int std::streambuf::write(char const* s, std::streamsize n) {
    std::lock_guard<std::mutex> guard(this->mutex);
    std::streamsize b = std::min(n, this->epptr() - this->pptr());
    memcpy(this->pptr(), s, b);
    this->pbump(b);
    bool success = true;
    if (this->pptr() == this->epptr()) {
        success = this->this->epptr() - this->pbase()
            != write(this->fd, this->pbase(), this->epptr() - this->pbase();
        // also ignoring partial writes
        this->setp(this->pbase(), this->epptr());
        memcpy(this->pptr(), s + b, n - b);
        this->pbump(n - b);
    }
    return success? n: -1;
}

第二个代码可能看起来有点复杂,但只针对 30 个字符执行一次。许多检查被移出了有趣的部分。即使完成了一些锁定,它也锁定了一个无竞争的互斥锁,不会过多地抑制处理。

特别是当不做任何分析时,使用 putchar_unlocked() 的循环将不会被优化太多。特别是,代码不会被矢量化,这会导致直接因子至少约为 3,但在实际循环中可能甚至接近 16。锁的成本将迅速降低。

顺便说一句,只是为了创建合理水平的 Playground :除了优化之外,您还应该在使用 C++ 标准流对象时调用 std::sync_with_stdio(false)

关于c++ - 为什么这种使用 putchar_unlocked 的方法打印字符串比 printf 和 cout 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32672689/

相关文章:

c++:有界数字的异构模板

c - fprintf 段错误

c - 如何将 ASCII 转换为十六进制,反之亦然?

c - 读函数从不在 C 中返回 0

c - 为什么我的代码只产生 0.000000 结果?

c - fputs 与 fprintf 和 double

c++ - 更好地理解 makefile - 在这种情况下如何生成 .o 文件

c++ - g++ lambda declared using local type ... 已使用但从未定义 - 真的是错误吗?

c++ - 如何在函数声明中声明 C++ mem_fn(member_function)?

C 中可以添加非常大的数字,但不能添加小数字