Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么使用putchar_unlocked的方法比printf和cout打印字符串慢?_C++_C_Printf_Cout_Putchar - Fatal编程技术网

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

C++ 为什么使用putchar_unlocked的方法比printf和cout打印字符串慢?,c++,c,printf,cout,putchar,C++,C,Printf,Cout,Putchar,我正在研究如何为编程竞赛加速我的代码,以此作为输入和输出处理的基本加速 我目前正在使用一个线程不安全的putchar_unlocked函数来打印一些测试。我认为,由于其线程可解锁的特性,如果能够很好地实现,那么对于某些数据类型,该函数比printf更快 我实现了一个函数,以这种方式打印字符串(在我看来,非常简单): void write_str(字符s[],整数n){ int i; 对于(i=0;i而言,选择更快的方式输出字符串会与使用的平台、操作系统、编译器设置和运行时库发生冲突,但有一些概括

我正在研究如何为编程竞赛加速我的代码,以此作为输入和输出处理的基本加速

我目前正在使用一个线程不安全的putchar_unlocked函数来打印一些测试。我认为,由于其线程可解锁的特性,如果能够很好地实现,那么对于某些数据类型,该函数比printf更快

我实现了一个函数,以这种方式打印字符串(在我看来,非常简单):

void write_str(字符s[],整数n){
int i;

对于(i=0;i而言,选择更快的方式输出字符串会与使用的平台、操作系统、编译器设置和运行时库发生冲突,但有一些概括可能有助于理解选择什么

首先,考虑操作系统可能有一种显示字符串的方法,与一次一个字符相比,如果这样的话,一次一个地调用一个字符输出的系统调用会自然地调用系统的每个调用的开销,而不是一个系统调用处理字符数组的开销。 这基本上就是你所遇到的,系统调用的开销

与putchar相比,putchar_unlocked的性能增强可能是相当大的,但仅在这两个函数之间。此外,大多数运行库都没有putchar_unlocked(我在较旧的MAC OS X文档中找到它,但在Linux或Windows中找不到)


也就是说,无论是锁定还是解锁,每个字符都会有开销,而处理整个字符数组的系统调用可能会消除这些开销,并且这些概念扩展到输出到文件或其他设备,而不仅仅是控制台。

选择更快的方式输出字符串会与平台、操作系统发生冲突,编译器设置和运行时库在使用中,但有一些概括可能有助于理解选择什么

首先,考虑操作系统可能有一种显示字符串的方法,与一次一个字符相比,如果这样的话,一次一个地调用一个字符输出的系统调用会自然地调用系统的每个调用的开销,而不是一个系统调用处理字符数组的开销。 这基本上就是你所遇到的,系统调用的开销

与putchar相比,putchar_unlocked的性能增强可能是相当大的,但仅在这两个函数之间。此外,大多数运行库都没有putchar_unlocked(我在较旧的MAC OS X文档中找到它,但在Linux或Windows中找不到)


也就是说,无论是锁定还是解锁,每个字符都会有开销,这可能会因为处理整个字符数组的系统调用而被消除,并且这种概念扩展到输出到文件或其他设备,而不仅仅是控制台。

假设多达10000000000个字符的时间测量值低于一个测量值t threshold和对
std::cout
stdout
的写入是使用批量写入的表单生成的(例如
std::cout.write(str,size)
),我猜
putcharu unlock()
除了放入字符外,大部分时间实际上都在更新数据结构的某些部分。其他批量写入操作将批量将数据复制到缓冲区中(例如,使用
memcpy()
),并在内部仅更新一次数据结构

也就是说,代码看起来是这样的(这是pidgeon代码,也就是说,只是大致显示发生了什么;真正的代码至少会稍微复杂一些):

<> Pode:批量代码的代码是沿着这条线做的(使用C++符号,因为它更容易成为C++开发者;再次,这是PiGeon代码):

int std::streambuf::write(字符常量*s,std::streamsize n){
std::lock\u guard(这个->互斥体);
std::streamsize b=std::min(n,this->epptr()-this->pptr());
memcpy(this->pptr(),s,b);
本->pbump(b);
布尔成功=真;
如果(this->pptr()==this->epptr()){
success=this->this->epptr()-this->pbase()
!=写入(this->fd,this->pbase(),this->epptr()-this->pbase();
//也忽略部分写入
this->setp(this->pbase(),this->epptr());
memcpy(this->pptr(),s+b,n-b);
这->pbump(n-b);
}
返回成功?n:-1;
}
第二个代码看起来可能有点复杂,但只对30个字符执行一次。许多检查都从感兴趣的位移出。即使完成了一些锁定,它也锁定了一个无争用的互斥体,不会对处理造成太大的抑制

尤其是在不使用
putchar\u unlocked()
对循环进行任何分析时,不会对循环进行太多优化。特别是,代码不会矢量化,这会导致acutal循环的立即因子至少为3,但可能更接近16。锁的成本将迅速降低


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

假定最多1兆个字符的时间测量值低于测量阈值,写为<>代码> STD::CUT和 STDUD> /COD>使用批量写入(如:代码> STD::COUT.Script(STR,size)< /C>)来制作。,我猜,
putchar\u unlock()
除了放入字符外,大部分时间实际上都在更新数据结构的某些部分。其他批量写入操作将批量将数据复制到缓冲区中(例如,使用
memcpy()
),并在内部仅更新一次数据结构

也就是说,代码看起来像这样(这是pidgeon代码,也就是说,只是粗略地显示发生了什么;真正的c
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;
}
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;
}