python - 提高在已安装文件夹中移动越来越多的大量文件的性能

标签 python performance file-io mount

这是我的情况:

A 有一个 Windows 网络共享,我用 mount -t cifs -o username=username,password=password,rw,nounix,iocharset=utf8,file_mode=0777,dir_mode=0777//192.168.1.120 安装/存储/mnt/存储

此文件夹包含数量快速增长的各种大小的文件(几个字节高达 ~20MB)。如果不移动/删除,此目录中的文件数量可能超过 1000 万。

我需要将具有特定名称 (*.fext) 的文件批处理(在 move_script 中)从该目录移动到另一个目录(当前是目录 /mnt/storage/in_progress).

然后该脚本启动另一个脚本 (process_script),该脚本将处理 /mnt/storage/in_progress 中的文件。 process_script 完成后,文件再次被 move_script 移动到另一个子目录 (/mnt/storage/done)。 move-process-move 继续进行,直到源文件夹 (/mnt/storage) 不再包含文件。

进程的附加信息:

  • 目前的瓶颈是文件的移动(文件移动速度比目录中创建文件快一点)

    if len(os.listdir("/mnt/storage") >= batch_size:
        i = 0
        for f in os.listdir("/mnt/storage"):
            if f.endswith(".fext"):
                move("/mnt/storage/+"f","/mnt/storage/in_progress"
                i+=1
            if i==batch_size:
                break
    
  • 脚本移动/开始处理文件,等待处理完成

  • /mnt/storage/in_progress 中文件的处理对于 1k-2k 文件的批处理是最快的。

  • 我已尝试让移动的文件数量不断增加。首先移动 1k,然后如果源目录中的文件数量在增长,则移动的文件数量加倍。这会减慢 process_script 中文件的处理速度,但有助于跟上“文件生成器”..

  • 我考虑过在process_script完成后将子目录/mnt/storage/in_progress简单重命名为"/mnt/storage/done"+ i_counter 并创建一个新的 /mnt/storage/in_progress。我假设这会将脚本中的移动时间减半。

我需要加快这个过程,以便跟上文件生成器的步伐。我怎样才能提高这个移动操作的性能?

我愿意接受任何建议,并愿意彻底改变我目前的做法。

编辑:脚本在 debian wheezy 上运行,所以理论上我可以使用发出 mv 的子进程,但我不知道这有多合理。

==========================================

编辑2: 我写了一个脚本来测试各种移动方法之间的速度差异。 首先创建 1x5GB(dd if=/dev/urandom of=/mnt/storage/source/test.file bs=100M count=50),然后创建 100x5MB(for i in {1 ..100}; 做 dd if=/dev/urandom of=/mnt/storage/source/file$i bs=1M count=5) 最后用 10000x5kB (for i in {1. .100000}; 做 dd if=/dev/urandom of=/mnt/storage/source/file$i bs=1k count=5)

from shutil import move
from os import rename
from datetime import datetime
import subprocess
import os

print("Subprocess mv: for every file in directory..")
s = datetime.now()
for f in os.listdir("/mnt/storage/source/"):
    try:
        subprocess.call(["mv /mnt/storage/source/"+str(f)+" /mnt/storage/mv"],shell=True)
    except Exception as e:
        print(str(e))
e = datetime.now()
print("took {}".format(e-s)+"\n")

print("Subprocessmv : directory/*..")
s = datetime.now()
try:
    subprocess.call(["mv /mnt/storage/mv/* /mnt/storage/mvf"],shell=True)
except Exception as e:
    print(str(e))
e = datetime.now()
print("took {}".format(e-s)+"\n")


print("shutil.move: for every file file in directory..")
s = datetime.now()
for f in os.listdir("/mnt/storage/mvf/"):
    try:    
        move("/mnt/storage/mvf/"+str(f),"/mnt/storage/move")
    except Exception as e:
        print(str(e))
e = datetime.now()
print("took {}".format(e-s)+"\n")

print("os.rename: for every file in directory..")
s = datetime.now()
for f in os.listdir("/mnt/storage/move/"):
    try:
        rename("/mnt/storage/move/"+str(f),"/mnt/storage/rename/"+str(f))
    except Exception as e:
        print(str(e))
e = datetime.now()
print("took {}".format(e-s)+"\n")


if os.path.isdir("/mnt/storage/rename_new"):
    rmtree('/mnt/storage/rename_new')
print("os.rename & os.mkdir: rename source dir to destination & make new source dir..")
s = datetime.now()
rename("/mnt/storage/rename/","/mnt/storage/rename_new")
os.mkdir("/mnt/storage/rename/")
e = datetime.now()
print("took {}".format(e-s)+"\n")

这表明没有太大区别。5GB 文件的移动速度非常快,这告诉我通过更改文件表进行的移动是有效的。这是 10000*5kB 文件的结果(感觉结果取决于当前的网络工作负载。例如,第一个 mv 测试耗时 2m 28s,之后相同的文件耗时 3m 22s,也是os.rename() 大多数时候是最快的方法..):

Subprocess mv: for every file in directory..
took 0:02:47.665174

Subprocessmv : directory/*..
took 0:01:40.087872

shutil.move: for every file file in directory..
took 0:01:48.454184

os.rename: for every file in directory..
rename took 0:02:05.597933

os.rename & os.mkdir: rename source dir to destination & make new source dir..
took 0:00:00.005704

最佳答案

您可以使用 glob 模块列出文件来简化代码。但最有可能的限制因素是网络。最有可能的是,这些文件最终会通过网络进行复制,而不是简单地移动。否则这个过程会非常快。

尝试使用 os.rename() 移动文件。它可能不适用于 cifs 文件系统,但值得一试。那应该进行实际的重命名,而不是复制。如果它不起作用,您可能需要以其他方式挂载该文件系统。或者在文件系统所在的机器上运行移动过程。

关于python - 提高在已安装文件夹中移动越来越多的大量文件的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26757374/

相关文章:

Python 计数函数在教程视频中没有增加

python - 如何在 Django 表单 ChoiceField 中获取选项标签?

performance - ORM 的当前状态是什么?

C:警告:格式 '%s' 需要匹配的 'char *' 参数

c - 为什么我的文件 IO 在 c 中无限循环?

python - Tensorflow 可视化工具 "Tensorboard"在 Anaconda 下不工作

python请求ssl错误550

performance - Sybase 上不区分大小写的搜索

当 SQL 包含带有 LIKE 的参数时,不使用 Oracle 语言索引

Java扫描仪检测空行?