重用Python字节数组/内存视图

4 投票
1 回答
4202 浏览
提问于 2025-04-18 01:06

我正在尝试通过一个套接字接收一系列的protobuf数据,但我事先不知道会有多少数据。我发送的数据量比较大,所以我需要在接收时对这些消息进行缓存,以确保我能收到所有的消息。我想利用Python中的bytearray和memoryview来避免不必要的数据复制。

目前,我使用的是字符串,并在接收到数据时将其追加到字符串中。这种方法简单,我可以通过类似下面的方式来“移动”这个“缓冲区”:

# Create the buffer
str_buffer = []

# Get some data and add it to our "buffer"
str_buffer += "Hello World"

# Do something with the data . . .

# "shift"/offset the message by the data we processed
str_buffer = str_buffer[6:]

有没有可能用bytearray或memoryview做类似的事情呢?

# Create the buffer/memoryarray 
buffer = bytearray(1024)
view   = memoryview(buffer)

# I can set a single byte
view[0] = 'a'

# I can "offset" the view by the data we processed, but doing this 
# shrinks the view by 3 bytes. Doing this multiple times eventually shrinks
# the view to 0.
view = view[3:]

问题出现在我尝试在末尾添加更多数据时。如果我对现有的视图进行“偏移”,那么这个视图的大小就会“缩小”,我能添加的数据就越来越少。有没有办法重新利用现有的memoryview,只是将数据向左移动呢?

*根据文档,我知道我不能调整数组的大小。我觉得“缩小”的感觉是我理解上的误会。

1 个回答

5

其实,你根本不需要提前知道会有多少数据要处理。只要一直读取数据,直到没有更多数据为止就可以了。

import socket, sys

HOST = 'localhost'        # The remote host
PORT = 50007              # The same port as used by the server

recvbuff = bytearray(16)
recvview = memoryview(recvbuff)

size = 0

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
    nbytes = s.recv_into(recvview)
    if not nbytes:
        break
    size += nbytes
    recvview = recvview[nbytes:]
    if not len(recvview):
        print "filled a chunk", recvbuff
        recvview = memoryview(recvbuff)

print 'end of data', recvbuff[:len(recvview)], size

s.close()

撰写回答