【问题标题】:Downloading file using multithreading in python在python中使用多线程下载文件
【发布时间】:2023-12-04 11:54:01
【问题描述】:

我正在尝试使用 python cgi 中的多线程将多个文件(ard 25k)放入一个 zip 文件中。我已经编写了下面的脚本,但不知何故,我得到的响应内容长度为 0,响应中没有数据。这是我第一次在 python 中使用多线程。我在代码中遗漏了什么。是否在发布数据之前就打印输出?

任何帮助将不胜感激。

这是我的代码:

b = StringIO()
z = zipfile.ZipFile(b, 'w', zipfile.ZIP_DEFLATED)

def read_file(link):
    fname = link.split('/')
    fname = fname[-1]
    z.write(link, fname)

if __name__ == '__main__':
    form = cgi.FieldStorage()
    fileLinks = form.getvalue("fileLink")

    p = Pool(10)
    p.map(read_file, fileLinks)
    p.close()
    p.join()
    z.close()
    zipFilename = "DataFiles-" + str(time.time()) + ".zip"   
    length = b.tell()
    sys.stdout.write(
        HEADERS % ('application/zip', zipFilename, zipFilename, length)
    )
    b.seek(0)
    sys.stdout.write(b.read())
    b.close()

相同代码的顺序版本:

 for fileLink in fileLinks:
     fname = fileLink.split('/')
     filename = fname[-1] 
     z.write(fileLink, filename)
z.close()

【问题讨论】:

  • 算法的单线程版本是否按预期工作?
  • 感谢评论,让我试试看。
  • 我尝试过使用单线程并将文件数限制为 1000。它不起作用。它给出了相同的响应,内容长度为零。
  • 那么问题不在于多线程!
  • 相同代码的顺序版本有效。将代码添加到问题中。

标签: python multithreading python-2.7 cgi python-multiprocessing


【解决方案1】:

问题应该是ZipFile.write()(一般是ZipFile)不是线程安全的。

您必须以某种方式序列化对 zip 文件的线程访问。这是一种方法(在 Python 3 中):

ziplock = threading.Lock()

def read_file(link):
    fname = link.split('/')
    fname = fname[-1]
    with ziplock:
        z.write(link, fname)

这样做应该没有任何优势,因为锁实际上在做的是序列化 zip 文件的创建。

此版本可能会实现一些并行化,它会在将文件内容添加到 zip 文件之前读取文件内容:

def read_file(link):
    fname = link.split('/')
    fname = fname[-1]
    # the file is read in parallel
    contents = open(link).read()
    with ziplock:
        # writes to the zip file a re serialized
        z.writestr(fname, contents)

然而,如果文件驻留在同一个文件系统上,则读取操作很可能就好像它们已被操作系统序列化一样。

因为它是文件,所以并行化的可能目标是进程中受 CPU 限制的部分,即压缩,而 zip 格式似乎无法做到这一点(因为zip 文件的行为类似于一个目录,因此每个write() 都必须离开状态,以便在close() 上生成完整的存档)。

如果您可以使用不同的压缩格式,则使用 gizp 进行压缩并使用 tar (tarfile) 作为存档格式,并行化无需锁定即可工作,因为每个文件可以并行读取和压缩,并且只有 tar 连接会串行完成(.tar.gz.tgz 存档格式)。

【讨论】:

  • 感谢您的回答。感谢你的帮助。我会试一试,然后告诉你。