本帖最后由 MoonCakeMC 于 2023-3-18 20:23 编辑
如题,应该不算纯提问吧
首先说下背景
打OI的人应该都知道
输入输出是很费时间的
所以会有一系列的卡常技巧
比如用scanf替代cin,printf替代cout
数据量再大的时候还可以自己写快读快出
之前我非常坚信
快读<scanf<cin(指时间
而且我非常坚信手写快读是最快的()
但是仍然众所周知
cin慢是因为有个东西叫sync_with_stdio
据说把它关了就能和scanf差不多了
但是前几天我突发奇想
于是写了个python来测速度
虽然说python运行速度非常令人诟病
但是拿来记个时我觉得是没问题的
于是就有了如下的神奇结果
(从long long下限到long long上限随机数据,同组数据重复测试10次取平均值)
(待会优化成不同组数据跑10次,不过结果应该一样)
用我的代码跑的结果不同的大佬也可以发一下
不过我在我两台配置差了不少的电脑上跑
虽然结果不同,但是名次和差的数量级是一样的
代码如下:
judge.py
cin.cpp
cin_without_sync.cpp
scanf.cpp
read.cpp
不知道为什么,关了同步的cin比快读还快一些
有大佬可以说一下为什么吗()
(关同步不比快读好背
)
(不过我的快读是我常用快读,还不是究极快读,待会试试究极快读)
经验+7/3,金粒+5,逃
如题,应该不算纯提问吧
首先说下背景
打OI的人应该都知道
输入输出是很费时间的
所以会有一系列的卡常技巧
比如用scanf替代cin,printf替代cout
数据量再大的时候还可以自己写快读快出
之前我非常坚信
快读<scanf<cin(指时间
而且我非常坚信手写快读是最快的()
但是仍然众所周知
cin慢是因为有个东西叫sync_with_stdio
据说把它关了就能和scanf差不多了
但是前几天我突发奇想
于是写了个python来测速度
虽然说python运行速度非常令人诟病
但是拿来记个时我觉得是没问题的
于是就有了如下的神奇结果

(从long long下限到long long上限随机数据,同组数据重复测试10次取平均值)
(待会优化成不同组数据跑10次,不过结果应该一样)
用我的代码跑的结果不同的大佬也可以发一下

不过我在我两台配置差了不少的电脑上跑
虽然结果不同,但是名次和差的数量级是一样的
代码如下:
judge.py
cin.cpp
cin_without_sync.cpp
scanf.cpp
read.cpp
不知道为什么,关了同步的cin比快读还快一些
有大佬可以说一下为什么吗()
(关同步不比快读好背


(不过我的快读是我常用快读,还不是究极快读,待会试试究极快读)
但是关了同步好像就不能用scanf了的来着,要是记错了就当个乐子吧,毕竟我才刚上手c++(
我就知道java那个sout里面很多个同步锁(
看来低耦合确实能挤出一些效率来
LinGCar 发表于 2023-3-18 20:32
我就知道java那个sout里面很多个同步锁(
如果我没记错,同步锁是 PrintStream 的锅
你不妨把它当成一个正常的 OutputStream 然后往里面扔 byte[] (确信)
C++?我只知道
Scanner in = new Scanner(System.in);
int a = in.nextInt();

Scanner in = new Scanner(System.in);
int a = in.nextInt();

DarkLiam 发表于 2023-3-18 20:28
但是关了同步好像就不能用scanf了的来着,要是记错了就当个乐子吧,毕竟我才刚上手c++( ...
我也记得是这样()
但是既然cin都高效率了为什么不直接cout

(不过cout的格式化输出确实比较难受)
有考虑编译器和汇编的情况嘛,如果要细究的话,就不能只停在高级语言的层面了

Doomsday_Envoy 发表于 2023-3-18 21:52
有考虑编译器和汇编的情况嘛,如果要细究的话,就不能只停在高级语言的层面了 ...
本来想考虑一下的

但是最近环境不太方便反汇编()
而且devcpp编译出来的好像不是很适合反汇编()
而且输入好像还涉及到什么缓冲区之类的
这我就真不懂了,而且感觉汇编会很复杂(

大佬愿意的话可以细究一下然后跟我说说

MoonCakeMC 发表于 2023-3-18 22:01
本来想考虑一下的
但是最近环境不太方便反汇编()
而且devcpp编译出来的好像不是很适合反汇编( ...
听你描述像是没系统性学过汇编,但即便精通也未必能回答这个问题,因为这是工程的而非理论的。从高级语言到汇编在逻辑上并不复杂,但实际使用需求以及版本更新迭代之后,这个过程的实现就很复杂多样了。
你应该听说过,编译器的功能五花八门;对于某些编程语言的比较有时候也涉及对其编译器的比较,这就是问题所在了。但我只是听过几个案例,不是专攻这些的,油管搬运的视频好像有不少是这种听上去无厘头问题的技术性解释,去搜搜看吧。
Doomsday_Envoy 发表于 2023-3-18 22:14
听你描述像是没系统性学过汇编,但即便精通也未必能回答这个问题,因为这是工程的而非理论的。从高级语言 ...
感谢大佬指路

确实没系统学过汇编,或者说根本没学过()
只不过是之前做逆向功能的时候散着看了看
编译器的问题倒是知道
但是还没测试

待会补测一下试试

之前试过,的确是这样,感觉很神奇(
所以我现在加sync_with_stdio已经成习惯了(
scanf printf 是 c 的做法,而 cpp 有自己的 cin 和 cout,为了兼容这两种做法,必须同步输入输出流,这是为了为了线程安全,因此你去同步以后,输入、输出流就不同步了,也就无法同时使用了。
可以这么理解,为了线程安全,于是同步,于是要付出性能代价。
如果你一定要问为什么解绑后 cin cout 更快,这个问题非常难以回答,太底层了,你可以这么想,毕竟 c++ 比 c 多两个加号。
普通快读其实没快多少,实际上那种手写缓冲区的快读才是比较快的,但是仅限于开 O2 的情况下
这里涉及到一些内存访问,几级cpu缓存的问题,以及 fread 的优势,实际上不开 O2 的话,后者优势不是那么大
可以这么理解,为了线程安全,于是同步,于是要付出性能代价。
如果你一定要问为什么解绑后 cin cout 更快,这个问题非常难以回答,太底层了,你可以这么想,毕竟 c++ 比 c 多两个加号。
普通快读其实没快多少,实际上那种手写缓冲区的快读才是比较快的,但是仅限于开 O2 的情况下
这里涉及到一些内存访问,几级cpu缓存的问题,以及 fread 的优势,实际上不开 O2 的话,后者优势不是那么大
以前我也做过类似的实验,数据如下:
下面开始猜测,未经证实,谨慎观看,错了打我 qwq
scanf和printf是基于格式化字符串的,而cin和cout估计是基于C++的一些特性,编译成直接的函数调用,少了解析字符串的过程
下面开始猜测,未经证实,谨慎观看,错了打我 qwq
scanf和printf是基于格式化字符串的,而cin和cout估计是基于C++的一些特性,编译成直接的函数调用,少了解析字符串的过程

要快还是得手写缓冲区