gpt4 book ai didi

python - Python 中更快的套接字

转载 作者:太空狗 更新时间:2023-10-30 01:23:40 26 4
gpt4 key购买 nike

我有一个用 Python 编写的服务器客户端,它通过 LAN 运行。该算法的某些部分密集使用套接字读取,执行速度比 almost the same one 慢 3-6 倍。用 C++ 编写。有哪些解决方案可以加快 Python 套接字读取速度?

我实现了一些简单的缓冲,我使用套接字的类如下所示:

import socket
import struct

class Sock():
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.recv_buf = b''
self.send_buf = b''

def connect(self):
self.s.connect(('127.0.0.1', 6666))

def close(self):
self.s.close()

def recv(self, lngth):
while len(self.recv_buf) < lngth:
self.recv_buf += self.s.recv(lngth - len(self.recv_buf))

res = self.recv_buf[-lngth:]
self.recv_buf = self.recv_buf[:-lngth]
return res

def next_int(self):
return struct.unpack("i", self.recv(4))[0]

def next_float(self):
return struct.unpack("f", self.recv(4))[0]

def write_int(self, i):
self.send_buf += struct.pack('i', i)

def write_float(self, f):
self.send_buf += struct.pack('f', f)

def flush(self):
self.s.sendall(self.send_buf)
self.send_buf = b''

P.S.:分析还显示大部分时间花在读取套接字上。

编辑: 因为数据是以已知大小的 block 接收的,所以我可以一次读取整个 block 。所以我将我的代码更改为:

class Sock():
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.send_buf = b''

def connect(self):
self.s.connect(('127.0.0.1', 6666))

def close(self):
self.s.close()

def recv_prepare(self, cnt):
self.recv_buf = bytearray()
while len(self.recv_buf) < cnt:
self.recv_buf.extend(self.s.recv(cnt - len(self.recv_buf)))

self.recv_buf_i = 0

def skip_read(self, cnt):
self.recv_buf_i += cnt

def next_int(self):
self.recv_buf_i += 4
return struct.unpack("i", self.recv_buf[self.recv_buf_i - 4:self.recv_buf_i])[0]

def next_float(self):
self.recv_buf_i += 4
return struct.unpack("f", self.recv_buf[self.recv_buf_i - 4:self.recv_buf_i])[0]

def write_int(self, i):
self.send_buf += struct.pack('i', i)

def write_float(self, f):
self.send_buf += struct.pack('f', f)

def flush(self):
self.s.sendall(self.send_buf)
self.send_buf = b''

recv'ing from socket 在此代码中看起来是最佳的。但是现在 next_intnext_float 成为第二个瓶颈,它们每次调用需要大约 1 毫秒(3000 个 CPU 周期)来解包。是否有可能使它们更快,就像在 C++ 中一样?

最佳答案

您最近的瓶颈在 next_intnext_float 中,因为您从 bytearray 创建中间字符串,并且因为您一次只解压一个值.

struct 模块有一个 unpack_from,它接受一个缓冲区和一个偏移量。这样效率更高,因为不需要从 bytearray 创建中间字符串:

def next_int(self):
self.recv_buf_i += 4
return struct.unpack_from("i", self.recv_buf, self.recv_buf_i-4)[0]

此外,struct 模块一次可以解包多个值。目前,您为每个值从 Python 调用到 C(通过模块)。减少调用它的次数并让它在每次调用中做更多的工作会更好:

def next_chunk(self, fmt): # fmt can be a group such as "iifff" 
sz = struct.calcsize(fmt)
self.recv_buf_i += sz
return struct.unpack_from(fmt, self.recv_buf, self.recv_buf_i-sz)

如果您知道 fmt 始终是 4 字节整数和 float ,您可以将 struct.calcsize(fmt) 替换为 4 * len(fmt).

最后,作为一个偏好问题,我认为这样读起来更清晰:

def next_chunk(self, fmt): 
sz = struct.calcsize(fmt)
chunk = struct.unpack_from(fmt, self.recv_buf, self.recv_buf_i)
self.recv_buf_i += sz
return chunk

关于python - Python 中更快的套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10742639/

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