并行文件写入是否有效?

2024-05-01 10:18:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我想知道并行文件写入是否有效。实际上,硬盘一次只有一个可用的读头。因此,硬盘驱动器可以一次完成一项任务。 但下面的测试(在python中)与我的预期相反:

要复制的文件约为1 Gb

脚本1(//task逐行读写同一文件10次):

#!/usr/bin/env python
from multiprocessing import Pool
def read_and_write( copy_filename ):
    with open( "/env/cns/bigtmp1/ERR000916_2.fastq", "r") as fori:
        with open( "/env/cns/bigtmp1/{}.fastq".format( copy_filename) , "w" ) as fout:
            for line in fori:
                fout.write( line + "\n" )
    return copy_filename

def main():
    f_names = [ "test_jm_{}".format(i) for i in range( 0, 10 ) ]
    pool = Pool(processes=4)
    results = pool.map( read_and_write, f_names )

if __name__ == "__main__":
    main()

脚本2(逐行读取和写入同一文件10次的任务):

#!/usr/bin/env python
def read_and_write( copy_filename ):
    with open( "/env/cns/bigtmp1/ERR000916_2.fastq", "r") as fori:
        with open( "/env/cns/bigtmp1/{}.fastq".format( copy_filename) , "w" ) as fout:
            for line in fori:
                fout.write( line + "\n" )
    return copy_filename

def main():
    f_names = [ "test_jm_{}".format(i) for i in range( 0, 10 ) ]
    for n in f_names:
        result = read_and_write( n )

if __name__ == "__main__":
    main()

脚本3(//task to copy 10 times a same file):

#!/usr/bin/env python
from shutil import copyfile
from multiprocessing import Pool
def read_and_write( copy_filename ):
    copyfile( "/env/cns/bigtmp1/ERR000916_2.fastq", "/env/cns/bigtmp1/{}.fastq".format( copy_filename) )
    return copy_filename

def main():
    f_names = [ "test_jm_{}".format(i) for i in range( 0, 10 ) ]
    pool = Pool(processes=4)
    results = pool.map( read_and_write, f_names )

if __name__ == "__main__":
    main()

脚本4(复制同一文件10次的任务):

#!/usr/bin/env python
from shutil import copyfile
def read_and_write( copy_filename ):
    copyfile( "/env/cns/bigtmp1/ERR000916_2.fastq", "/env/cns/bigtmp1/{}.fastq".format( copy_filename) )
    return copy_filename

def main():
    f_names = [ "test_jm_{}".format(i) for i in range( 0, 10 ) ]
    for n in f_names:
        result = read_and_write( n )

if __name__ == "__main__":
    main()

结果:

$ # // task to read and write line by line 10 times a same file
$ time python read_write_1.py

real    1m46.484s
user    3m40.865s
sys 0m29.455s

$ rm test_jm*
$ # task to read and write line by line 10 times a same file
$ time python read_write_2.py

real    4m16.530s
user    3m41.303s
sys 0m24.032s

$ rm test_jm*
$ # // task to copy 10 times a same file
$ time python read_write_3.py

real    1m35.890s
user    0m10.615s
sys 0m36.361s


$ rm test_jm*
$ # task to copy 10 times a same file
$ time python read_write_4.py

real    1m40.660s
user    0m7.322s
sys 0m25.020s
$ rm test_jm*

这些基本结果似乎表明//io读写更有效率。

谢谢你的光


Tags: andinenvformatforreadmaindef
1条回答
网友
1楼 · 发布于 2024-05-01 10:18:04

I would like to know if parallel file writing is efficient.

简而言之:在物理上从多个线程同时写入同一个磁盘永远不会比从一个线程写入磁盘快(这里指的是normal硬盘)。在某些情况下甚至会慢很多。

但是,一如既往,这取决于很多因素:

  • 操作系统磁盘缓存:写操作通常由操作系统保存在缓存中,然后分块写入磁盘。因此,多个线程可以同时写入该缓存而不会出现问题,这样做具有速度优势。尤其是在处理/准备数据的时间比磁盘的写入速度长的情况下。

  • 在某些情况下,甚至当从多个线程直接写入物理磁盘时,操作系统也会对此进行优化,只向每个文件写入大的块。

  • 然而,在最坏的情况下,每次都可以将较小的数据块写入磁盘,从而需要硬盘查找(在普通硬盘上为±10ms!)在每个文件交换机上(在SSD上执行同样的操作不会那么糟糕,因为有更多的直接访问,不需要查找)。

因此,一般来说,当从多个线程同时写入磁盘时,最好在内存中准备(某些)数据,并使用某种锁将最终数据以较大的块写入磁盘,或者从一个专用的写入线程写入。如果文件在写入时正在增长(即前面没有设置文件大小),将数据写入较大的块也可以防止磁盘碎片(至少尽可能多)。

在一些系统上可能根本没有区别,但在另一些系统上,它可能会产生很大的区别,并变得慢得多(甚至在同一个系统上有不同的硬盘)。

要很好地测试使用单线程与多线程时的写入速度差异,总文件大小必须大于可用内存,或者至少在测量结束时间之前,所有缓冲区都应刷新到磁盘。仅测量将数据写入操作系统磁盘缓存所需的时间在这里没有多大意义。

理想情况下,将所有数据写入磁盘所测量的总时间应等于物理硬盘的写入速度。如果使用一个线程写入磁盘的速度比磁盘写入速度慢(这意味着处理数据比写入数据需要更长的时间),显然使用更多线程会加快速度。如果多个线程的写入速度比磁盘写入速度慢,则由于在不同文件(或同一个大文件中的不同块)之间切换而导致磁盘查找时间丢失。

为了了解执行大量磁盘查找时的时间损失,让我们看一些数字:

假设我们有一个写速度为50MB/s的硬盘:

  • 写入一个50MB的连续块需要1秒(在理想情况下)。

  • 在1MB的块中执行同样的操作,使用文件开关并在两者之间产生磁盘寻道将提供:20毫秒写入1MB+10毫秒寻道时间。写50MB需要1.5秒。这是50%的时间增长,只是在两者之间做了一个快速搜索(同样的从磁盘读取也一样-考虑到更快的读取速度,差异甚至会更大)。

实际上,它将介于两者之间,这取决于系统。

虽然我们希望操作系统能够很好地处理所有这些问题(或者使用IOCP等),但情况并非总是如此。

相关问题 更多 >