MoonCakeMC
本帖最后由 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,逃

DarkLiam
但是关了同步好像就不能用scanf了的来着,要是记错了就当个乐子吧,毕竟我才刚上手c++(

Stone_ingot
  特性,都是特性  

LinGCar
我就知道java那个sout里面很多个同步锁(

teddyxlandlee
看来低耦合确实能挤出一些效率来

teddyxlandlee
LinGCar 发表于 2023-3-18 20:32
我就知道java那个sout里面很多个同步锁(

如果我没记错,同步锁是 PrintStream 的锅
你不妨把它当成一个正常的 OutputStream 然后往里面扔 byte[] (确信)

霖丶
C++?我只知道
Scanner in = new Scanner(System.in);
int a = in.nextInt();

MoonCakeMC
DarkLiam 发表于 2023-3-18 20:28
但是关了同步好像就不能用scanf了的来着,要是记错了就当个乐子吧,毕竟我才刚上手c++( ...

我也记得是这样()
但是既然cin都高效率了为什么不直接cout
(不过cout的格式化输出确实比较难受)

Doomsday_Envoy
有考虑编译器和汇编的情况嘛,如果要细究的话,就不能只停在高级语言的层面了

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

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

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

Doomsday_Envoy
MoonCakeMC 发表于 2023-3-18 22:01
本来想考虑一下的
但是最近环境不太方便反汇编()
而且devcpp编译出来的好像不是很适合反汇编( ...

听你描述像是没系统性学过汇编,但即便精通也未必能回答这个问题,因为这是工程的而非理论的。从高级语言到汇编在逻辑上并不复杂,但实际使用需求以及版本更新迭代之后,这个过程的实现就很复杂多样了。
你应该听说过,编译器的功能五花八门;对于某些编程语言的比较有时候也涉及对其编译器的比较,这就是问题所在了。但我只是听过几个案例,不是专攻这些的,油管搬运的视频好像有不少是这种听上去无厘头问题的技术性解释,去搜搜看吧。

MoonCakeMC
Doomsday_Envoy 发表于 2023-3-18 22:14
听你描述像是没系统性学过汇编,但即便精通也未必能回答这个问题,因为这是工程的而非理论的。从高级语言 ...

感谢大佬指路
确实没系统学过汇编,或者说根本没学过()
只不过是之前做逆向功能的时候散着看了看

编译器的问题倒是知道
但是还没测试
待会补测一下试试

_tms
之前试过,的确是这样,感觉很神奇(
所以我现在加sync_with_stdio已经成习惯了(

极光creeper
scanf printf 是 c 的做法,而 cpp 有自己的 cin 和 cout,为了兼容这两种做法,必须同步输入输出流,这是为了为了线程安全,因此你去同步以后,输入、输出流就不同步了,也就无法同时使用了。

可以这么理解,为了线程安全,于是同步,于是要付出性能代价。

如果你一定要问为什么解绑后 cin cout 更快,这个问题非常难以回答,太底层了,你可以这么想,毕竟 c++ 比 c 多两个加号。

普通快读其实没快多少,实际上那种手写缓冲区的快读才是比较快的,但是仅限于开 O2 的情况下
这里涉及到一些内存访问,几级cpu缓存的问题,以及 fread 的优势,实际上不开 O2 的话,后者优势不是那么大




开心的阿诺
以前我也做过类似的实验,数据如下:

下面开始猜测,未经证实,谨慎观看,错了打我 qwq
scanf和printf是基于格式化字符串的,而cin和cout估计是基于C++的一些特性,编译成直接的函数调用,少了解析字符串的过程

inuEbisu
要快还是得手写缓冲区

MoonCakeMC
inuEbisu 发表于 2023-3-18 23:43
要快还是得手写缓冲区

确实是()
但是感觉打OI的时候手写缓冲区没啥必要
(应该不会有题还卡快读吧……

第一页 上一页 下一页 最后一页