关于缓冲区以及输出方式

news/2025/10/4 20:16:26/文章来源:https://www.cnblogs.com/Dawn-chen/p/19125885

先有个前置知识:

  1. CPU 速度差不多是 I/O 设备的 \(10^6\) 倍这样
  2. CPU 访问内存的顺序:L1 缓存 → L2 缓存 → L3 缓存 → 主内存 → I/O设备
  3. 系统调用发生在「主内存 → I/O 设备」这一步中
  4. 缓冲区通常设置在主内存中
为什么要有缓冲区?

一个现实问题:
很显然的,CPU 速度相对于 I/O 设备来说太快了,CPU 常常需要等待 I/O 设备完成输入输出,从而导致 CPU 利用率低下。

一个传统解法:
既然每次都要跑一遍「L1 缓存 → L2 缓存 → L3 缓存 → 主内存 → I/O设备」这个流程,中间还要有系统调用这个特别慢的流程,那么不如多堆一点数据等会一起调出得了

就像送快递,把快递一个一个从转运中心送到客户家门口效率低得吓人,但把快递装成一车,就省得跑这么多路,从而提高了效率(虽然这个样子效率依旧感人)

这个时候,「缓冲区」这个概念应运而生。

它是在内存中开辟的一小块空间,用于暂时存放 CPU 计算完毕的数据,并在缓冲区满后通过系统调用把存放的数据一起给 I/O 设备。

按照「生产者-消费者问题」来看的话,我们可以把 CPU 比做生产者,把 I/O 设备比做消费者,数据比做商品。

那么缓冲区的意义,就在于把生产者和消费者解耦,让它们可以以各自的速度运行下去,避免一方被另一方的速度卡着的情况发生。

交互题的诡异函数:

我们知道,在交互题中,我们经常可以看到如下说法:

每次输出后不要忘记换行并刷新输出缓冲区,否则会收到 Idleness limit exceeded 的判罚。具体做法如下:
C++:fflush(stdout) 或 cout.flush()
Java:System.out.flush()
Pascal:flush(output)
Python:stdout.flush()
其它语言请查阅相关文档。

我们知其然,却不知其所以然。为什么我一定要清空缓冲区?我不清空怎么你了?

但如果我们知道了以上做法有什么用处,或许上面的问题就可以迎刃而解了。

让我们以 c++ 为例:

在默认情况下,c++ 标准输出(cout)通常是行缓冲(在终端)或者是全缓冲(在重定向到文件时)的。行缓冲,指的是遇到换行符(\n)或者是缓冲区满的时候清空一次缓冲区;全缓冲,指的是只在缓冲区满的时候清空一次缓冲区。

在 CSP、NOIP 一类需要提交文件的的比赛中或者是在洛谷、OpenJudge 等在线 OJ 中,由于程序运行时的输出被重定向到文件中,所以使用的缓冲方式是全缓冲,即在缓冲区满的时候清空才清空一次缓冲区。

众所周知,交互题具有非常强的实时性,几乎要求一个输入对应一个实时的输出。但是,从上文我们得知,由于缓冲区的存在以及全缓冲的使用,导致一大堆输出要等到缓冲区满之后才能被调到 I/O 设备进行操作。而这又违背了交互题的本质——交互:

程序等待评测机给出输入从而得以继续处理数据并最终输出,评测机等待程序的输出从而给出下一个输入。

这是什么?这是死锁!而这也是 Idleness limit exceeded 判罚的原因。

于是出题人处心积虑(?),从 iostream 库里翻出来这么一个函数—— cout.flush()

cout.flush() 的用处是清空缓冲区,此处的清空指的是强制进行系统调用把数据从缓冲区调出到 I/O 设备进行 I/O 操作。

这么一来,我们得以实现与评测机的实时交互,也从此出现了一种新题型:交互题。

不同输出方式的比较:

我们还是以 c++ 为例展开说明:

c++标准库提供了流操作符endl、flush和ends来刷新输出缓冲区。endl操作符输出换行符并刷新缓冲区,flush仅刷新缓冲区而不输出任何内容,而ends输出一个空字符后刷新缓冲区。
—— OI Wiki

由于 ends 在竞赛语境下不实用且不使用,本文略去。

同时,我们有两种主流的换行方式:其一,使用 endl 换行;其二,使用换行符 "\n" 换行;

由上可知,使用 endl 不仅换行,并且会清空缓冲区。而使用 "\n" 只会换行,并不会清空缓冲区。使用 cout.flush() 只会清空缓冲区,不会换行。

这里重点讲一下这三种方法的时间开销:

使用 endl 需要清空缓冲区,由上文可知,这个操作也可以看成要进行一次系统调换。但众所周知,进行系统调换,就意味着有巨大的时间开销,就意味着在有大量输出的情况下程序有 TLE 的风险。

使用 "\n" 不需要清空缓冲区,可以减少 I/O 负担,程序效率得到有效提高。

(关于它们效率的比较数据见 Q & As)

在竞赛里这似乎不用犹豫了直接无脑选择 "\n" 就行了。

顺带一提,由上文我们可知,清空缓冲区意味着程序运行到这一行的时候一定会进行 I/O 操作。那就意味着,要是我在之后的程序中有危险操作(比如说爆栈),我仍然可以得到这一行之前的输出。

意即,要是我们使用 endl 进行换行(或是直接使用 cout.flush()),我们可以得到危险操作之前的输出;而要是使用 "\n" 进行换行的话,我们就不能得到之。

具体测试就不放出来了,有心的读者可以自行测试。

关于 ios::syuc_with_stdio(false) (本段需要结合计组知识食用)

使用 std::ios::sync_with_stdio(false) 函数来关闭与 C 流的同步。
对于基于流的 I/O(如 std::cin 与 std::cout),最常用的优化方法为关闭与 C 流的同步与解除输入输出流的关联。
——OI Wiki

还是众所周知,关闭同步流,即 ios::sync_with_stdio(false) ,可以极大地优化 c++ 标注输入(cin)输出(cout)的时间开销。

但是,我们还是知其然不知其所以然。本段将探讨其个中原理。

我们都知道,在 c++ 语境下, c 的标准输出(printf())和 c++ 的标准输出 (cout)是共用一个缓冲区的。

c 和 c++ 的混合输出,实质上是在竞争使用 I/O 设备。由于 I/O 设备是处于临界区的资源,所以需要一个对其进行保护。我们使用一个实例进行讲解:

cout << "Hello World!\n";
printf("Hello World\n");

如上的代码块混合使用 c 和 c++ 的 I/O。 当执行到 cout << "Hello World!\n"; 时,其需要获取 I/O 设备的;当执行到 printf("Hello World\n"); 时,其也需要获取 I/O 设备的。程序执行的底层时间线如下:

[cout 获取锁] → [cout 输出] → [释放锁] → [printf 获取锁] →
[printf 输出] → [释放锁]

(在 [cout 输出],[释放锁],[printf 获取锁] 这三个步骤中,这段时间printf 在等待锁)

上述步骤中,时间开销的主要来源一般有两个:

第一,锁竞争的开销。在每一次 I/O 操作中,都需要进行「获取锁 → 检查 c/c++ 流的状态 → 协调缓冲区 → 实际输出操作 → 更新双方状态 → 释放锁」这一大串操作,时间开销自然增加。

第二,状态协调的开销。在每一次 I/O 操作中,也都需要进行「检查 c/c++ 流的状态 → 更新 c++/c 流的状态 → 维护缓冲区的一致性 → 处理错误状态同步」等操作,时间开销也会增加。

如果使用 ios::sync_with_stdio(false) 关闭同步流,把缓冲区一分为二,以上的操作通通都不用管—— c 和 c++ 流各自管理自己的缓冲区,无锁的竞争,无状态的协调,从而减少时间开销。

但,好处说完了,代价呢?

代价就是不能保证 c/c++ 流的同步。 由于 c/c++ 流的异步,会导致输入输出的乱序。

由于在终端中使用的是行缓冲,所以你的输出看上去没有什么问题(当然也有可能乱序)。但是,当我们把代码提交的时候,由于输出被重定向到文件,使用的是全缓冲,有时可能会捕获不到另一个流的输出,导致有些本应有的输出没有了(是的,本人就是因为这一点被卡过一个晚上)

Q & As:
  1. Q :那既然系统调用的速度比 I/O 设备还要慢,那为什么还要设计缓冲区呢?下一个数据从 CPU 调到 I/O 设备的时间已经足够 I/O 设备完成上一个数据的 I/O 操作了啊?设计缓冲区岂不是降低了 I/O 设备的利用率?
    A:从整体上考量,如果没有缓冲区的话,那么 CPU 要等待系统调用完毕才能进行下一次计算。而这,又降低了 CPU 的利用率。我们引进缓冲区,是希望 CPU 和 I/O 设备能够并行处理。这样虽然看似降低了 I/O 设备的利用率,实则不然,只是把原先串行的 I/O 操作转化为了并行的 I/O 操作,从整体上考量的话,这种方案是更优的。
  2. Q:你说的数据比较呢我怎么没见到?
    A:由于我一上来就搞了四千万行的输出,加诸我的电脑太烂了QWQ,最后只找到一组不完整的数据QWQ。源码如下,有心的读者可以自行测试。(感谢 A1234467提供的代码,本人稍作修改)
#include<stdio.h>  
#include<time.h>  
#include<conio.h>  
#include<windows.h>  
#include<iostream>  int main() {  
    const int times = 10000000;  
    system("cls");  
    freopen("test.txt", "w", stdout);  
    clock_t c1 = clock();  
    for (int i = 0; i < times; i++) std::cout << std::endl;  
    clock_t c2 = clock();  
    for (int i = 0; i < times; i++) std::cout << "\n";  
    clock_t c3 = clock();  
    for (int i = 0; i < times; i++) printf("\n");  
    clock_t c4 = clock();  
    //for (int i = 0; i < times; i++)  
    //clock_t c5 = clock();  
    system("cls");  
    std::cout << "write times:%d\n" << times;  
    std::cout << double(c2 - c1) / CLOCKS_PER_SEC << double(c3 - c2) / CLOCKS_PER_SEC << double(c4 - c3) / CLOCKS_PER_SEC;  
        std::ios::sync_with_stdio(false);  
    std::cin.tie(0);  
    clock_t c5 = clock();  
    for (int i = 0; i < times; i++) std::cout << std::endl;  
    clock_t c6 = clock();  
    std::cout << double(c6 - c5) / CLOCKS_PER_SEC << "s" << std::endl;  
    return 0;  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/927510.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

asp网站可运行jsp吗wordpress接入安卓

在计算机使用过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中“找不到msvcr120.dll”就是常见的一种。那么&#xff0c;找不到msvcr120.dll是什么意思呢&#xff1f; 一&#xff0c;msvcr120.dll文件概述 msvcr120.dll 是 Microsoft Visual C Redistributable …

详细介绍:2025三掌柜赠书活动第三十五期 AI辅助React Web应用开发实践:基于React 19和GitHub Copilot

详细介绍:2025三掌柜赠书活动第三十五期 AI辅助React Web应用开发实践:基于React 19和GitHub Copilot2025-10-04 20:11 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: norm…

网站推广设计制作专做女装拿货的网站

目录 1、向量点乘 2、相似度计算举例 3、QKV分析 4、整体流程 (1) 首先从词向量到Q、K、V (2) 计算Q*&#xff08;K的转置&#xff09;&#xff0c;并归一化之后进行softmax (3) 使用刚得到的权重矩阵&#xff0c;与V相乘&#xff0c;计算加权求和。 5、多头注意力 上面…

深圳建设银行宝安支行网站市场营销在线课程

1. JVM快速入门 从面试开始&#xff1a; 请谈谈你对JVM 的理解&#xff1f;java8 的虚拟机有什么更新&#xff1f; 什么是OOM &#xff1f;什么是StackOverflowError&#xff1f;有哪些方法分析&#xff1f; JVM 的常用参数调优你知道哪些&#xff1f; 内存快照抓取和MAT分…

coduck模拟赛一 补题报告 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

RippleNet: Propagating User Preferences on the Knowledge Graph for Recommender Systems

1.知识图谱嵌入的基本过程,为什么难以直观有效表达项目间的关系 1.1基本过程(知识图谱嵌入)构建三元组: 将知识图谱表示为(头实体h, 关系r, 尾实体t)集合。向量化建模: 为每个实体、关系分配可学习的向量/矩阵,常见…

特地拎出来的总结

这篇总结不太一样,为了纪念和我爸喋喋不休吵了近3h的时间和教训,用Deepseek共同完成 : 题目 T674176 T2-任务task 题目描述 时间限制: 2.0 秒 空间限制: 512 MiB 有 \(n\) 个任务,第 \(i\) 个任务需要占据 \([l_…

在线做漫画的网站wordpress多用户评论

文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0c;可直观的展示主题的研究发展历程、研究现状、研究…

漏洞赏金计划的困境:i915漏洞与ChromeOS、Intel赏金项目剖析

本文深入探讨了漏洞赏金计划存在的系统性问题,通过作者亲身经历的i915驱动漏洞案例,揭示了Google和Intel在处理安全漏洞报告过程中的沟通不畅、缺乏透明度等问题,并分析了漏洞赏金计划中权力失衡的根本原因。漏洞赏…

wordpress站名在哪改项目协同管理平台

在 Unix 环境下&#xff0c;" 寄存器需要 xterm-clipboard feature 的 VIM 软件才能使用&#xff0c;具有这个 feature 的 VIM 可以安装 vim-gtk&#xff08;包含gvim和vim&#xff09;&#xff0c;使用 gvim 可以正常调用 " 寄存器。

2025异型件厂家推荐:邯郸市烁燊紧固件,广泛应用于建筑、桥梁、机械、电力、交通等诸多领域

在现代工业体系中,异型件作为关键基础零部件,广泛应用于建筑、桥梁、机械、电力、交通等诸多领域。随着各行业的快速发展,对异型件的质量、性能和精度等方面提出了更高的要求。在这样的背景下,邯郸市烁燊紧固件有限…

C++设计模式之行为型模式:解释器模式(Interpreter) - 详解

C++设计模式之行为型模式:解释器模式(Interpreter) - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Cons…

免费的小程序模板网站做网站服务公司

一、 搜索算法 深度优先搜索和广度优先搜索是最暴力的图的搜索算法。算法的目标是&#xff0c;给定一张图&#xff0c;一对初始和终止节点&#xff0c;找到两节点之间的节点路径。&#xff08;代码均是找到两个节点之间的路径&#xff09; 广度优先搜索是一层一层搜索&#xf…

中国最大网站建设商网站生成器怎么做

python绑定项目 官方未提供python的封装绑定&#xff0c;直接调用执行文件 https://github.com/stlukey/whispercpp.py提供了源码和Cpython结合的绑定 https://github.com/zhujun1980/whispercpp_py提供了ctype方式的绑定&#xff0c;需要先make libwhisper.so Pybind11 bi…

dede视频网站宣城市住房和城乡建设局网站首页

关注公号【逆向通信猿】更精彩!!! 1. 构造编码器对象 采用MATLAB内置的comm.LDPCEncoder构造编码器对象,其中使用默认的校验矩阵,信息位长32400比特,码长64800比特,该校验矩阵中除第一行中1的个数为6个外,其余行中1的个数均为7;前12960列中1的个数为8,后32400列构成…

如何备份一个网站广西住建局

1. C/C++ IDE 安装Clion Nova和VsCode 2. 编译器 2.1 g++ 当程序比较小时,安装g++编译器进行编译,常用命令如下: // 安装g++ sudo apt-get install g++ // 默认生成a.out的可执行文件 g++ main.cpp // 生成其他名字的可执行文件 g++ main.cpp -o exe_name2.2 cmake 当…

网站开发一次性费用网站建设公司发展方向及趋势

2020年9月10日&#xff0c;亚马逊通技术服务&#xff08;北京&#xff09;有限公司&#xff08;AWS中国&#xff09;与毕马威企业咨询&#xff08;中国&#xff09;有限公司&#xff08;毕马威中国&#xff09;宣布已签署战略合作协议。 双方将充分利用各自的全球品牌影响力和资…

深入解析:PostgreSQL向量检索:pgvector入门指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

网贷之家网站建设你访问的网站正在建设

以上问题在编译器中出现可以在编译器中最上面加入&#xff1a; #define_CRT_SECURE_NO_WARNINGS 或者将scanf修改为scanf_s 一定要在最上端&#xff01;&#xff01;&#xff01;最上端&#xff01;&#xff01;&#xff01;最上端加入&#xff01;&#xff01;&#xff01; 虽…

Allow or block media autoplay in Firefox

https://support.mozilla.org/en-US/kb/block-autoplay