使用不是2的幂的bufsize调用socket.recv的实际影响是什么?

Rus*_*uss 30 c python sockets tcp

要从python中的套接字读取数据,请调用socket.recv,它具有以下签名:

socket.recv(bufsize[, flags])

socket.recvpython文档模糊地陈述:

注意:为了最好地匹配硬件和网络现实,bufsize的值应该是2的相对较小的幂,例如4096.

问题:" 最符合硬件和网络现实 "是什么意思?将bufsize设置为非二次幂的实际影响是什么?

我已经看到许多 其他的 建议,使这个读取2的幂.我也很清楚,当数组长度为2的幂时通常有用的原因(长度上的位移/屏蔽操作,最佳FFT数组大小等),但这些是依赖于应用程序的.我只是没有看到它的一般原因socket.recv.当然不是python文档中具体建议的要点.我也没有看到底层python代码中的任何二次幂优化,使其成为特定于python的推荐

例如......如果您有一个协议,其中传入的数据包长度是完全已知的,那么显然最好只读取"最多"您正在处理的数据包所需的内容,否则您可能会吃掉下一个数据包那会很烦人.如果我正在处理的数据包只有42个字节待处理,我只会将bufsize设置为42.

我错过了什么?当我必须选择任意缓冲区/数组大小时,我通常(总是?)使长度为2的幂,以防万一.这只是多年来养成的习惯.python文档也只是习惯的受害者吗?

这不是python独有的,但由于我特意引用了python文档,我会将其标记为.


更新:我刚刚在我的系统上检查了内核级缓冲区的大小(或者至少我认为我做了......我做了cat /proc/sys/net/core/rmem_default)并且它是124928.不是2的强大. rmem_max是131071,也显然不是两个人的力量.

在研究这个问题时,我真的看不出两项建议的力量有什么好处.我准备将其称为虚假推荐......

我还添加tcpC标签,因为他们也与此有关.

Mar*_*ers 6

我很确定"2的强力"建议是基于编辑错误而不应被视为一项要求.

为了回应Python问题#756104,这条特定的建议被添加到Python 2.5文档中(并向后移植到Python 2.4.3文档).记者使用了一个不合理的大缓冲区大小,这促使更新.socket.recv()

Tim Peters引入了"2的力量"概念:

我希望你是历史上唯一一个尝试将如此大的值传递给recv()的人 - 即使它有效,你几乎肯定会耗尽内存,试图为1.9GB分配缓冲区空间.套接字是一种低级设施,通常传递相对较小的2的幂(以便与硬件和网络现实最佳匹配).

(大胆强调我的).我和蒂姆一起工作过,他在网络编程和硬件方面有着丰富的经验,所以一般来说,在做这样的评论时我会接受他的话.他特别喜欢Windows 95堆栈,因为它在压力下失败的能力,他称之为煤矿中的金丝雀.但请注意,他说这很常见,而不是需要使用2的幂.

正是这一措辞导致了文档更新:

这是一个文档错误; 用户应该被"警告"的东西.

这抓住了我一次,两个不同的人在#python中询问了这个问题,所以也许我们应该在recv()文档中添加如下内容.

msgstr"""
为了最好地匹配硬件和网络现实,
"缓冲区" 的值应该是2的相对较小的幂,
例如,4096.
""

如果您认为措辞是正确的,只需将错误分配给我,我会照顾它.

没有人在这里挑战"2的力量"断言,但是编辑从中移动是很常见应该是在一些回复的空间.

对我来说,那些提出文档更新的人更关心的是确保使用一个小缓冲区,而不是它是否是2的幂.但这并不是说它不是一个好的建议 ; 任何与内核交互的低级缓冲区都会与内核数据结构保持一致.

但是,尽管可能存在一个深奥的堆栈,其中大小为2的幂的缓冲区更重要,但我怀疑蒂姆·彼得斯是否意味着他的经验(通常的做法)是用这样的铁腕术语来表达的.如果不同的缓冲区大小对您的特定用例更有意义,请忽略它.

  • 雅,"2的力量"在这里是一个红鲱鱼.特定的套接字实现可能有也可能不支持特定的缓冲区大小,但是"bug"报告解析的真正要点是阻止海报尝试使用多GB的缓冲区.顺便说一句,Win95的价值在于发现Python(&Zope)中的错误.它的线程和套接字很好,但与当时的Unix-y系统有着截然不同的语用(如时序).在Win95上运行压力测试发现了一个合法的错误世界! (4认同)