我尝试编写一个python程序,该程序使用python的套接字将文件从一台PC发送到另一台PC。但是,当文件大小增加时,将花费大量时间。是否可以使用线程顺序读取文件的行?
我认为的概念如下: 每个线程分别从文件中依次读取行,并通过套接字发送。有可能吗?或您对此有何建议?
答案 0 :(得分:3)
首先,如果您想在不使用线程的情况下尽可能加快速度,那么一次读取和发送一行可能会很慢。 Python很好地缓冲了文件,一次给您一行以供读取,但随后您通过网络发送了72个字节的小数据包。您想尝试一次至少发送1.5KB。
理想情况下,您想使用sendfile
方法。 Python会告诉操作系统以最有效的方式通过套接字发送整个文件,而完全不会涉及您的代码。不幸的是,这在Windows上不起作用。如果您对此感到担心,则可能想直接使用pywin32
到本机API 1 或切换到更高级别的网络库,例如twisted
或{{1} }。
现在,如何处理线程?
好吧,一次在不同线程中读取一行不会有很大帮助。线程必须顺序读取,并争夺文件对象中的读取指针(和缓冲区),并且它们大概必须顺序写入套接字,甚至可能需要互斥体以确保它们按顺序写入内容。因此,无论哪一个速度最慢,您的所有线程都将最终等待轮到他们。 2
此外,甚至忘记了套接字:在现代硬件上,在某些情况下,并行读取文件 可能会更快,但是一般却要慢得多。假设文件位于慢速磁硬盘上。一个线程试图读取第一个块,下一个线程试图读取第64个块,下一个线程试图读取第4个块……这意味着您比实际读取数据花费更多的时间来回搜索磁盘。
但是,如果您认为自己可能处于并行读取可能会帮助的情况之一,则可以尝试一下。这不是小事,但并不难。
首先,您要对固定大小的块进行二进制读取。您将需要尝试不同的大小-也许4KB是最快的,也许是1MB ...所以请确保将其设置为常数,以便您可以在代码中的一个位置轻松更改。
接下来,您希望能够尽快获得数据,而不是序列化。这意味着您必须在每个块之前发送某种标识符,例如文件中的偏移量。
该函数将如下所示:
asyncio
…,除了(除非您的文件实际上是def sendchunk(sock, lock, file, offset):
with lock:
sock.send(struct.pack('>Q', offset)
sent = sock.sendfile(file, offset, CHUNK_SIZE)
if sent < CHUNK_SIZE:
raise OopsError(f'Only sent {sent} out of {CHUNK_SIZE} bytes')
的所有倍数)外,您需要确定要对合法EOF进行的处理。也许在任何块之前发送总文件大小,并用空字节填充最后一个块,然后让接收者截断最后一个块。
然后,接收方可以循环读取8 + CHUNK_SIZE个字节,解压缩偏移量,查找并写入字节。
1。请参阅TransmitFile
-但是要使用它,您必须知道如何在Python级CHUNK_SIZE
对象和Win32级socket
之间进行切换,依此类推;如果您从未这样做过,那将是学习的弯道-而且我不知道有一个好的教程可以帮助您入门。.
2。如果您真的很幸运,并且文件读取的速度仅是套接字写入速度的两倍,那么实际上您可以从流水线中获得33%的加速-也就是说,一次只能写入一个线程,但是等待写入的线程大部分已经完成了读取,因此至少您不需要在那里等待。
答案 1 :(得分:0)
不是线程。
source_path = r"\\mynetworkshare"
dest_path = r"C:\TEMP"
file_name = "\\myfile.txt"
shutil.copyfile(source_path + file_name, dest_path + file_name)
https://docs.python.org/3/library/shutil.html
Shutil提供了使用OS层进行复制的高级复制功能。对于这种情况,这是您最好的选择。