使用 Python 提高 UDP 传输速度的最佳方法?
Best way to improve UDP transfer speeds with Python?
我编写了一个 Python 程序用于通过 UDP 发送和接收大文件。现在,通过 10 吉比特以太网电缆在两台计算机之间传输时,我可以达到大约 0.01GB/s 的速度。我希望显着提高该速度,但不确定最佳方法是什么。
为了它的价值,我必须使用 UDP 进行传输。我写的程序只是一个更大项目的测试,发送该项目数据的设备不能使用 TCP 流。此外,我主要关注快速接收数据报的最佳方式,或者至少是确保接收端不会出现任何瓶颈的最佳方式。
现在,我的程序通过将一个大文件分成几部分来工作,这些部分将成为要发送的数据报。这些数据报被发送,然后接收方做一些事情以确保它获得正确的数据并相应地对其进行排序。
发送代码(简化为基础)
buf = 32000 #Size of each chunk/packet
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
host ="127.0.0.1"
port = 5005
addr = (host,port)
def read_in_chunks(infile, chunk_size=buf):
"""Chunk the file before we send it.
Arguments:
infile -- the file to chunk
chunk_size -- the size of the chunk in bytes (default 32KB)
"""
while True:
chunk = infile.read(chunk_size)
if chunk:
yield chunk
else:
# The chunk was empty, which means we're at the end of the file
return
def run():
for chunk in read_in_chunks(f):
if(s.sendto(chunk,addr) and s.sendto(id,addr)):
#Some acknowledgment stuff - removed for clarity (also noted to not impact performance)
local_ID += 1
接收码:
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
buf = 32000 # Buffer size in bytes for each chunk
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
try:
while(dataChunk):
actualNumChunks += 1
f.write(dataChunk)
sock.settimeout(2)
dataChunk, addr = sock.recvfrom(buf)
packID, junkAddr = sock.recvfrom(buf)
packIDString = str(packID)
except socket.timeout:
f.close()
sock.close()
print "File received!" # --KEEP
print "A total of " + str(actualNumChunks) +" chunks were received" --KEEP
我不确定优化我的代码是否是问题所在(尚未测试),或者是否有另一种(更好的?)提高文件传输速度的方法。如果这里的细节不够详细,我深表歉意,但如果您需要更多信息,请告诉我。
谢谢!
尝试的一些方法:
- 不同的数据包大小(取决于 MTU,可能会导致块被分割成几个数据包,或者可能太小而无法最佳地使用管道)
- 将文件读入内存(网络速度可能是10gbps,但磁盘速度慢得多,尤其是如果它不是SSD - 通常慢一个数量级或更慢),完成后开始发送被缓存。您可以尝试多次发送相同的数据块以检查是否是瓶颈。
- 压缩可能会有所帮助。 ZLIB 非常非常非常快,这意味着您可以在更短的时间内传输更多的数据,
其他要点:
- 数据包丢失和排序可能会使正确的传输出现问题,即使是在简单的 1 对 1 link 中也是如此。您需要 error-detection/retry 功能才能正常工作。
- Kernel/User 模式更改可能会减慢您的速度(怀疑它,这是超级微优化)
对于您的接收器,您进行文件写入,这可能是一个瓶颈。要尝试的几件事是将所有“dataChunk”写入队列。然后有一个单独的线程或进程(多处理)从这个队列中读取,写入文件。这将从您的 while 循环中卸载文件写入 IO,并可能允许您处理更多数据包。
我编写了一个 Python 程序用于通过 UDP 发送和接收大文件。现在,通过 10 吉比特以太网电缆在两台计算机之间传输时,我可以达到大约 0.01GB/s 的速度。我希望显着提高该速度,但不确定最佳方法是什么。
为了它的价值,我必须使用 UDP 进行传输。我写的程序只是一个更大项目的测试,发送该项目数据的设备不能使用 TCP 流。此外,我主要关注快速接收数据报的最佳方式,或者至少是确保接收端不会出现任何瓶颈的最佳方式。
现在,我的程序通过将一个大文件分成几部分来工作,这些部分将成为要发送的数据报。这些数据报被发送,然后接收方做一些事情以确保它获得正确的数据并相应地对其进行排序。
发送代码(简化为基础)
buf = 32000 #Size of each chunk/packet
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
host ="127.0.0.1"
port = 5005
addr = (host,port)
def read_in_chunks(infile, chunk_size=buf):
"""Chunk the file before we send it.
Arguments:
infile -- the file to chunk
chunk_size -- the size of the chunk in bytes (default 32KB)
"""
while True:
chunk = infile.read(chunk_size)
if chunk:
yield chunk
else:
# The chunk was empty, which means we're at the end of the file
return
def run():
for chunk in read_in_chunks(f):
if(s.sendto(chunk,addr) and s.sendto(id,addr)):
#Some acknowledgment stuff - removed for clarity (also noted to not impact performance)
local_ID += 1
接收码:
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
buf = 32000 # Buffer size in bytes for each chunk
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
try:
while(dataChunk):
actualNumChunks += 1
f.write(dataChunk)
sock.settimeout(2)
dataChunk, addr = sock.recvfrom(buf)
packID, junkAddr = sock.recvfrom(buf)
packIDString = str(packID)
except socket.timeout:
f.close()
sock.close()
print "File received!" # --KEEP
print "A total of " + str(actualNumChunks) +" chunks were received" --KEEP
我不确定优化我的代码是否是问题所在(尚未测试),或者是否有另一种(更好的?)提高文件传输速度的方法。如果这里的细节不够详细,我深表歉意,但如果您需要更多信息,请告诉我。
谢谢!
尝试的一些方法:
- 不同的数据包大小(取决于 MTU,可能会导致块被分割成几个数据包,或者可能太小而无法最佳地使用管道)
- 将文件读入内存(网络速度可能是10gbps,但磁盘速度慢得多,尤其是如果它不是SSD - 通常慢一个数量级或更慢),完成后开始发送被缓存。您可以尝试多次发送相同的数据块以检查是否是瓶颈。
- 压缩可能会有所帮助。 ZLIB 非常非常非常快,这意味着您可以在更短的时间内传输更多的数据,
其他要点:
- 数据包丢失和排序可能会使正确的传输出现问题,即使是在简单的 1 对 1 link 中也是如此。您需要 error-detection/retry 功能才能正常工作。
- Kernel/User 模式更改可能会减慢您的速度(怀疑它,这是超级微优化)
对于您的接收器,您进行文件写入,这可能是一个瓶颈。要尝试的几件事是将所有“dataChunk”写入队列。然后有一个单独的线程或进程(多处理)从这个队列中读取,写入文件。这将从您的 while 循环中卸载文件写入 IO,并可能允许您处理更多数据包。