gpt4 book ai didi

python - python3.6 : socket. recv()vs socket.recv_into()性能

转载 作者:行者123 更新时间:2023-12-03 12:07:14 26 4
gpt4 key购买 nike

我一直在使用python3.6捕获高速udp流,并尝试了socket.recv()socket.recv_into()。我期望recv_into()更快,因为每次读取数据包并将其附加到列表后,它都会直接复制到“preallocatedbytearray中,而不是creating a new string中。
我的测试场景是核心绑定(bind)的,我知道我正在丢弃一些数据包,并且有很大的套接字通过setsockopt上的SO_RCVBUF接收缓冲区大小。我还关闭了垃圾收集器以避免随机中断。
以下代码片段具有类似的性能,这对我来说并没有意义,并且想知道是否有人可以帮助指出我所缺少的内容。谢谢!

pkts = []
while time.time() - t_start < 10.0:
pkt = s.recv(2048)
pkts.append(pkt)
num_recv_captured = len(pkts)

buffer = bytearray(2048)

num_recv_into_captured = 0
while time.time() - t_start < 10.0:
s.recv_into(buffer, 2048)
num_recv_into_captured += 1
在核心绑定(bind)方案中,我在这里看到 num_recv_into_capturednum_recv_captured类似,但是期望 num_recv_into_captured更大一些。

最佳答案

性能评估非常困难。您看到的结果可能是由于您的测试方法存在问题,或者可能是结果太接近而无法察觉。
因此,首先看一下您要比较的两种方法。您可能会认为唯一的区别是第二个不需要分配新的缓冲区,这是真正的区别,而有意义的键是唯一的,但不是唯一的。如果那是唯一的区别,那么您会期望它可以更快地可靠地运行,但这不是唯一的区别。第二种方法还采用了Python需要解析和处理的附加动态鸭子类型参数。这不应该花那么多时间,但是很难说与分配2048个字节所花费的时间相比如何,这将取决于解释器所使用的方法。 Python使用全局内存池,并且在没有其他任何事情的情况下处于紧密循环中,这很可能一遍又一遍地快速重新分配和重新分配相同的内存,而无需调用任何OS函数。
这就引出了下一个问题:尽管很难确定这两个操作的成本(也许其他人会更清楚地知道这两个都是有意义的),但它们的规模却与网络通信的规模不尽相同。您正在查看性能的纳秒级/微秒级差异,因为它们与毫秒级网络操作有关。您不仅可以调用操作系统并等待IO,而且在接收数据的速度比发送数据的速度快的情况下,操作系统很容易使进程陷入休眠状态,尤其是在您确实受到核心限制的情况下。您还提到不一定是确定性的数据包丢失。
如果您真的很在意这种性能规模,则应该使用C/C++或Rust或另一种允许您进行低级别访问的语言,或者编写C/C++或Cython模块,并使用该模块直接将C套接字库与python一起使用(如果您的目标平台是linux,则甚至可以使用recvmmsg来真正提高性能)。您可能不会。我不会出于实验目的而对实验感到怀疑(当您问这样的问题时,我实际上发现它很烦人,互联网上的人们只是向您解释为什么不打扰您,因为您不需要它之类的东西,所以),如果那是您可能会学到的情况是,微观优化通常几乎没有差别。
如果您要决定在较大的项目中使用哪种方法,请执行以下操作:如果您有任何理由为了方便起见而不愿选择另一个,则只需使用该一个即可。如果您真的担心性能,我会坚持使用recv_into。即使通话速度不比recv快。如果您有一个有意义的应用程序调用该方法,则它的内存特性将发挥作用,并且我希望系统在没有所有很小的分配和取消分配的情况下都能更好地运行,而这些分配和取消分配不可能像它们在您的方法中那样完美地对齐小基准测试循环。
编辑:为了清楚起见,在这种情况下,数据包丢失不是确定性的,因为系统上正在进行的其他操作没有被准确地记录和重复...即,我想说它在理论上总是确定性的,但是它是实际上,您是观察者无法理解的。
编辑2:我突然想到您提到禁用垃圾收集。这只会禁用收集器,但是基于引用计数的内存释放仍然应该发生,因此紧密的recv循环有可能一遍又一遍地释放并重新分配相同的内存块,因为它是由CPython而不是OS分配的,并且少量的内存可能很快就会完成。
编辑3:太晚了...无论如何,我只是注意到您正在将所有数据包添加到recv下的列表中,因此您将不会重新分配和重新分配内存,而只是保留它们并在其中存储内存地址列表结构应该是一个非常快速的操作。不取消分配内存意味着您将不会重复使用相同的地址,但是这也意味着不需要进行取消分配,与分配给内存相比,分配额外的2048字节块仍然非常快。操作系统并返回以填充缓冲区。与任何OS发起的进程 sleep 相比,这些操作也将显得苍白。

关于python - python3.6 : socket. recv()vs socket.recv_into()性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65694746/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com