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

时间:2011-06-15 19:55:29

标签: python c sockets tcp

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

  

socket.recv(bufsize[, flags])

python docs for socket.recv含糊不清的状态:

  

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

问题:“与硬件和网络现实最匹配”是什么意思?将bufsize设置为非二次幂的实际影响是什么?

我已经看到many other recommendations使这个读数变为2的幂。我也很清楚将数组长度作为幂通常有用的原因两个(长度上的位移/屏蔽操作,最佳FFT阵列大小等),但这些是依赖于应用程序的。我只是没有看到socket.recv的一般原因。当然不是python文档中的specific recommendation。我也没有看到underlying python code中的任何二次幂优化使其成为特定于python的推荐

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

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

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


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

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

我还添加了tcpC标记,因为它们也相关。

2 个答案:

答案 0 :(得分:6)

我很确定'2的强力'建议是基于编辑错误,不应该被视为要求

针对added to the Python 2.5 documentation,该特定建议为backported to Python 2.4.3 docs(和Python issue #756104)。记者使用了一个不合理的大缓冲区大小socket.recv(),这促使了更新。

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

  

我希望你是历史上唯一尝试过这样的人   recv()的一个很大的值 - 即使它工作,你几乎   当然为了分配缓冲区空间而耗尽内存   1.9GB。套接字是一个低级设施,是常见的   传递相对较小的2的幂(为了最佳匹配   硬件和网络现实。)

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

然后导致文档更新的措辞是:

  

这是一个文档错误;用户应该做的事情   “警告”。

     

这引起了我一次,两个不同的人问起了   这个在#python中,所以也许我们应该把它放在像   以下是recv()文档。

     

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

     

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

没有人在这里挑战'2的权力'断言,但编辑从移动到通常 应该在一些回复的空间中。

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

但是虽然可能存在一个深奥的堆栈,其中大小为2的幂的缓冲区更重要,但我怀疑蒂姆·彼得斯对他的经验有意义(它是常规练习)以这种铁腕的方式演绎。如果不同的缓冲区大小对您的特定用例更有意义,请忽略它。

答案 1 :(得分:3)

关于:“如果你有一个协议,其中传入的数据包长度是完全已知的,显然最好只读”最多“你正在处理的数据包需要什么,否则你可能会吃下一个数据包,这将是恼人的。“

这对于应用程序开发人员来说可能更合适,但对于底层网络堆栈来说可能效率低下。首先,它绑定了可用于其他网络I / O的套接字缓冲区空间。其次,你创建的每个recv()意味着进入系统调用/内核空间,并且转换会有性能损失。最好是尽可能少的系统调用从内核空间中获取尽可能多的数据并进入用户空间,并在那里进行消息解析。这增加了应用程序代码和消息处理的复杂性,但可能是最有效的。

尽管如此,考虑到当今处理器的速度和可用内存量,对于大多数应用程序来说这可能不是问题,但这是“过去”中网络应用程序的常见建议。

我不确定用户空间应用程序的2推荐能力。由于对齐和页面大小问题等原因,我已经看到了驱动程序的这些类型要求,但不清楚它对用户空间有什么影响,除非它以某种方式帮助将数据从内核缓冲区复制到用户缓冲区。也许有更多操作系统开发知识的人可以评论。