为什么我的脚本会在删除数百万个文件时定期冻结?

Voi*_*oyd 1 python linux filesystems performance delete-file

我的目标是从中删除1000万个临时文件dir.所以,我试着写一个Python脚本来做这件事.第一个场景看起来像这样:

#!/usr/bin/python

import os,sys
dirname = os.getcwd() if len(sys.argv) == 1 else sys.argv[1]
deleteConfirm = raw_input('Delete all files from dir ' + str(dirname) + ' (y/n)? ')
if(deleteConfirm not in ['y','Y']):
    os._exit(0)

counter = 0
flist = os.listdir(dirname)
for file in flist:
    os.remove(os.path.join(dirname, file))
    counter+=1
    if(0==counter%1000):
        sys.stdout.write('\rDeleted %d files' % counter)
        sys.stdout.flush()

print '\nDeleted %d files' % counter
Run Code Online (Sandbox Code Playgroud)

这段代码有效,但我发现它每隔10-15秒就会停止一次,并且在大约一分钟左右不起作用.例如,前几秒场景快速输出已删除文件的数量 - 它只删除28 000个文件仅3-5秒,但随后它的输出在"已删除的28000个文件"上停止并等待很长时间 - 分钟左右.然后再次输出快速更新,并在几秒钟内再次删除数千个文件.但它又一次停下来等待着什么.我认为这是由于锁定文件,所以我尝试使用python3和多处理模块编写新方案,以删除几个进程中的文件.我认为它可能会有所帮助,因为即使一个进程等待某个文件要取消时钟,其他进程也会完成它们的工作.

是新脚本:

#!/usr/bin/python3

import os, sys, time
from multiprocessing import Pool
dirname = os.getcwd() if len(sys.argv) == 1 else sys.argv[1]
procNum = 5 if len(sys.argv) < 3 else sys.argv[2]
deleteConfirm = input('Delete all files from dir ' + str(dirname) + ' (y/n)? ')
if(deleteConfirm not in ['y','Y']):
    sys.exit()

def main():
    flist = os.listdir(dirname) 
    count = len(flist)
    if count < 100000:
        counter = 0
        for file in flist:
                os.remove(os.path.join(dirname, file))
                counter+=1
                if(0==counter%1000):
                    sys.stdout.write('\rDeleted %d files' % counter)
                    sys.stdout.flush()
            print('\rDeleted %d files' % counter)
            sys.exit(0)
        else:
            workers = Pool(processes=procNum)       
            result = workers.imap_unordered(delfile,flist)
        workers.close()
        while True:
                    time.sleep(5)
                    completed = result._index
                    if completed == count:
                        print('')
                        break
                    sys.stdout.write('\rRemoved %d files' % result._index)
            workers.join()

def delfile(fname):
    os.remove(os.path.join(dirname,fname))
Run Code Online (Sandbox Code Playgroud)

我尝试了这个新脚本,但它像前一个场景一样每隔几秒就停止一次.我无法弄清楚,为什么会这样.有任何想法吗?

Arm*_*igo 5

详细信息在Linux文档中,假设您使用的是Linux(其他操作系统可能不同):请参阅https://www.kernel.org/doc/Documentation/sysctl/vm.txt.

Linux通过创建"脏页"来处理对磁盘的写入,这些"脏页"是等待物理复制到磁盘的内存部分.物理副本后来出现.这就是为什么os.remove()通常非常快:它只是在内存中创建或修改页面并保留物理副本以供日后使用.(如果很快,我们会做另一个os.remove()需要更改相同内存页面的内容,那么我们就赢了:不需要多次将此页写入磁盘.)

通常,名为"pdflush"的守护程序会定期唤醒以执行此写入磁盘.但是如果一个进程真的产生了很多脏页面,那么内核会在某一时刻停止它(在随机的一个os.remove()调用期间)并强制写入磁盘现在发生,对于一些未决页面.它只允许程序在脏页再次低于合理阈值时继续.可能,"pdflush"将立即继续写其余部分.显然,如果您的程序继续生成脏页,它将再次达到上限并再次暂停.

这是导致过程暂停的原因.这是内核如何工作的副作用.您可以忽略它:物理上,磁盘一直处于忙碌状态.