1

私の目標は、から 1,000 万個の一時ファイルを削除することでした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

このコードは機能しますが、10 ~ 15 秒ごとに停止し、1 分程度は機能しないことがわかりました。たとえば、最初の数秒のシナリオでは、削除されたファイルの数がすぐに出力されます。28,000 個のファイルが 3 ~ 5 秒間だけ削除されますが、その後、「28,000 個のファイルが削除されました」というメッセージで出力が停止し、長時間 (1 分程度) 待機します。次に、出力が再びすばやく更新され、数秒で数千のファイルが削除されます。しかし、再び停止し、何かを待っています。これはロックされたファイルが原因だと思うので、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))

この新しいスクリプトを試してみましたが、前のシナリオと同様に数秒ごとに停止します。なぜこれが起こっているのか分かりません。何か案は?

4

1 に答える 1

5

Linux を使用していると仮定して、詳細は Linux のドキュメントに記載されています (他の OS は異なる場合があります)。たとえば、https://www.kernel.org/doc/Documentation/sysctl/vm.txtを参照してください。

Linux は、ディスクへの物理コピーを保留しているメモリのセクションである「ダーティ ページ」を作成することによって、ディスクへの書き込みを処理します。物理コピーは後で提供されます。そのためos.remove()、通常は非常に高速です。メモリ内でページを作成または変更し、物理コピーを後で使用できるようにします。(すぐに、os.remove()メモリの同じページを変更する必要がある別のことを行う場合、勝ちです。このページをディスクに何度も書き込む必要はありません。)

通常、「pdflush」と呼ばれるデーモンが定期的に起動して、このディスクへの書き込みを行います。しかし、プロセスが実際に大量のダーティ ページを生成する場合、カーネルはある時点でプロセスを停止し (呼び出しのランダムなos.remove()呼び出し中に)、保留中のページの一部に対してディスクへの書き込みを強制的に実行します。ダーティ ページが再び妥当なしきい値を下回った場合にのみ、プログラムの続行が許可されます。おそらく、「pdflush」はすぐに残りの書き込みを続行します。明らかに、プログラムがダーティ ページを生成し続けると、再び上限に達し、再び一時停止します。

これが、プロセスの一時停止の原因です。これは、カーネルの動作の副作用です。これは無視できます。物理的に、ディスクは常にビジー状態です。

于 2013-05-23T20:57:41.467 に答える