0

我想在python cgi中使用多线程将多个文件(ard 25k)放入一个zip文件中。我写了下面的脚本,但不知怎的,我得到的响应内容长度为0,响应中没有数据。这是我第一次在python中使用多线程。代码中是否有任何缺少的内容?即使在数据发布之前,输出是否被打印?在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() 
+1

算法的单线程版本是否按预期工作? – Apalala

+0

感谢您的评论,让我试试看。 –

+0

我尝试过使用单线程并将文件数限制为1000.它不起作用。它给出与零内容长度相同的响应。 –

回答

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文件的创建。

一些并行化可能与此版本,将其添加到压缩文件之前读取文件内容来实现:

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文件的行为像一个目录,所以每write()必须离开状态准备产生一个完整的档案close())。

如果你可以使用不同的压缩格式,然后并行将工作,而无需使用压缩gizp焦油锁tarfile)为存档格式,每个文件可以被并行读取和压缩,只将连续进行(.tar.gz.tgz存档格式)。

+0

感谢您的回答。感谢你的帮助。我会尝试一下,让你知道。 –