2

試み#2:

人々は私がやろうとしていることを理解していないようです。私がそれをより明確に述べることができるかどうか見てみましょう:

1)ファイルのリストを読み取ることは、ディレクトリを歩くよりもはるかに高速です。

2)では、ディレクトリをウォークし、結果のリストをファイルに書き込む関数を作成しましょう。さて、将来、そのディレクトリ内のすべてのファイルを取得したい場合は、ディレクトリを歩く代わりに、このファイルを読み取ることができます。このファイルをインデックスと呼びます。

3)明らかに、ファイルシステムが変更されると、インデックスファイルは同期しなくなります。これを克服するために、ファイルシステムへの変更を監視するためにOSにフックする別のプログラムがあります。それらの変更をモニターログと呼ばれるファイルに書き込みます。特定のディレクトリのインデックスファイルを読み取った直後に、監視ログを使用してさまざまな変更をインデックスに適用し、ディレクトリの現在の状態を反映させます。

ファイルの読み取りはディレクトリを歩くよりもはるかに安価であるため、これは最初の呼び出し以降のすべての呼び出しを歩くよりもはるかに高速であるはずです。

元の投稿:

任意のディレクトリ内のすべてのファイルを再帰的に取得し、さまざまなパラメータに従ってそれらをフィルタリングする関数が必要です。そして、私はそれを速くしたいのです。たとえば、単にdirを歩くよりも1桁速くなります。そして私はPythonでそれをしたいと思います。クロスプラットフォームが望ましいですが、Windowsが最も重要です。

これについての私の考えは次のとおりです。

all_filesという関数があります。

def all_files(dir_path, ...parms...):
    ...

この関数を初めて呼び出すと、os.walkを使用して、すべてのファイルのリストが、非表示かどうか、シンボリックリンクなどのファイルに関する情報とともに作成されます。このデータをファイルに書き込みます。ディレクトリ内の「.index」と呼ばれます。以降のall_filesの呼び出しで、.indexファイルが検出され、dirをウォークするのではなく、そのファイルを読み取ります。

これにより、ファイルが追加および削除されるときにインデックスが同期しなくなるという問題が残ります。そのために、起動時に実行され、ファイルシステム全体に対するすべての変更を検出し、それらを「mod_log.txt」というファイルに書き込む2番目のプログラムがあります。ここで説明する方法のように、Windows信号を介して変更を検出します。このファイルには、行ごとに1つのイベントが含まれ、各イベントは、影響を受けるパス、イベントのタイプ(作成、削除など)、およびタイムスタンプで構成されます。.indexファイルには、最後に更新された時刻のタイムスタンプも含まれます。all_filesの.indexファイルを読み取った後、mod_log.txtをテールし、タイムスタンプの後に発生したイベントを.indexファイルで見つけます。これらの最近のイベントを取得し、現在のディレクトリに適用されるイベントを見つけて、それに応じて.indexを更新します。

最後に、すべてのファイルのリストを取得し、さまざまなパラメーターに従ってフィルター処理して、結果を返します。

私のアプローチについてどう思いますか?これを行うためのより良い方法はありますか?

編集:

このコードをチェックしてください。再帰的なウォークでキャッシュされたリストを読み取ることで、大幅なスピードアップが見られます。

import os
from os.path import join, exists
import cProfile, pstats

dir_name = "temp_dir"
index_path = ".index"

def create_test_files():
    os.mkdir(dir_name)
    index_file = open(index_path, 'w')
    for i in range(10):
        print "creating dir: ", i
        sub_dir = join(dir_name, str(i))
        os.mkdir(sub_dir)
        for i in range(100):
            file_path = join(sub_dir, str(i))
            open(file_path, 'w').close() 
            index_file.write(file_path + "\n")
    index_file.close()
#

#  0.238 seconds
def test_walk():            
    for info in os.walk("temp_dir"):
        pass

#  0.001 seconds
def test_read():
    open(index_path).readlines()

if not exists("temp_dir"):
    create_test_files()

def profile(s):
    cProfile.run(s, 'profile_results.txt')
    p = pstats.Stats('profile_results.txt')
    p.strip_dirs().sort_stats('cumulative').print_stats(10)

profile("test_walk()")
profile("test_read()")
4

6 に答える 6

7

ファイルシステムがすでに実行している作業を複製しようとしないでください。あなたはそれがすでにしているよりもうまくやるつもりはありません。

あなたの計画には多くの点で欠陥があり、桁違いの改善は得られません。

欠陥と潜在的な問題:

ファイルシステムのスナップショットを常に使用します。あなたはそれが現実から大きく切り離されていないことを確実に知ることは決してないでしょう。それがアプリケーションの動作パラメータの範囲内であれば、汗を流さないでください。

ファイルシステム監視プログラムは、ファイルシステムを再帰的にウォークする必要があるため、作業はまだ行われています。

キャッシュの精度を上げるには、ファイルシステムモニターを実行する頻度を増やす必要があります。実行回数が多いほど、節約できる実際の時間は少なくなります。

ファイルシステムモニタープログラムによって更新されている間、クライアントアプリケーションはインデックスファイルを読み取ることができない可能性が高いため、クライアントがインデックスが読み取り可能になるのを待つ間、時間が失われます。

私は続けることができました。

実際、現実とは非常に切り離されている可能性のあるファイルシステムのスナップショットを操作する必要がない場合は、インデックスをメモリに保持し、アプリケーション自体から更新する方がはるかに良いと思います。これにより、他の方法で発生するファイル競合の問題が解消されます。

于 2010-01-13T20:20:40.457 に答える
3

最良の答えは、MichałMarczykから最初の質問のコメントリストの一番下に向かって来ました。彼は、私が説明していることはUNIXロケートプログラムに非常に近いと指摘しました。ここでWindowsバージョンを見つけました:http://locate32.net/index.php。それは私の問題を解決しました。

編集:実際には、すべての検索エンジンはさらに良く見えます。どうやらWindowsはファイルシステムへの変更のジャーナルを保持しており、Everythingはそれを使用してデータベースを最新の状態に保ちます。

于 2010-01-15T22:41:10.137 に答える
2

Windows Desktop Searchは、副産物などのインデックスを提供しませんか?Macでは、スポットライトインデックスで次のようなファイル名を照会できますmdfind -onlyin . -name '*'

もちろん、ディレクトリを歩くよりもはるかに高速です。

于 2010-01-13T20:41:52.563 に答える
1

簡単な答えは「いいえ」です。Pythonで、ファイルシステムを1桁上回るインデックスシステムを構築することはできません。

ファイルシステムの「インデックス作成」は、キャッシングの実装に関係なく、集中的/低速なタスクです。ファイルシステムインデックスを構築する際の大きなオーバーヘッドを回避する唯一の現実的な方法は、大きなトラバーサルを回避するために「インデックスを作成する」ことです。(結局のところ、ファイルシステム自体はすでにデータインデクサーです。)

この「ビルドアズユーゴー」ファイルシステムインデックス作成を実行できるオペレーティングシステム機能があります。これは、OSX上のSpotlightやWindowsデスクトップ検索などのサービスの基盤です。

ディレクトリを歩くよりも高速になることを期待するには、これらのOSまたはファイルシステムレベルのツールのいずれかを活用する必要があります。

また、作業を別の時間/プロセスに「移動」したという理由だけで、解決策がより速いと誤解しないようにしてください。あなたのサンプルコードはまさにそれをします。同じファイルを作成してインデックスを作成しているときに、サンプルファイルのディレクトリ構造をトラバースし、後でそのファイルを読み取るだけです。

ここには2つのレッスンがあります。(a)適切なテストを作成するには、「セットアップ」を「テスト」から分離することが不可欠です。ここで、パフォーマンステストは基本的に、「ディレクトリ構造をトラバースするか、事前に作成されたインデックスを読み取る方が速いですか?」と述べています。明らかに、これはリンゴとオレンジの比較ではありません。

しかし、(b)あなたは同時に正解に出くわしました。既存のインデックスを使用すると、ファイルのリストをはるかに高速に取得できます。これは、Windowsデスクトップ検索やSpotlightインデックスなどを活用する必要がある場所です。

間違いなく、ファイルシステムのインデックスを作成するには、定義上、すべてのファイルに「アクセス」する必要があります。ファイルがツリーに保存されている場合、再帰的トラバーサルがすべてのファイルにアクセスできる最速の方法になる可能性があります。質問が「Pythonコードを記述して、正確に何をするかを実行できますos.walkが、それよりも桁違いに高速であるかos.walk」という場合、答えは断然ノーです。「実際にすべてのファイルにアクセスする時間をとらずに、システム上のすべてのファイルにインデックスを付けるPythonコードを記述できますか」という質問の場合でも、答えはノーです。

「私がやろうとしていることをあなたが理解していないと思う」に応じて編集してください

ここで明確にしましょう。事実上、ここの誰もがあなたがやろうとしていることを理解しています。あなたは「いいえ、これはあなたが望むようには機能しないでしょう」と私たちが理解していないことを意味しているようです。

これを別の角度から見てみましょう。ファイルシステムは、当初から現代のコンピューティングに不可欠なコンポーネントでした。データの分類、索引付け、保存、および取得は、コンピューターサイエンスとコンピューターエンジニアリングの重要な部分であり、コンピューターサイエンスの最も優秀な頭脳の多くが絶えず取り組んでいます。

ファイルの属性/メタデータ/データに基づいてファイルをフィルタリング/選択できるようにする必要があります。これは、コンピューティングで常に利用される非常に一般的なタスクです。現在使用しているコンピューターでも、1秒間に数回発生する可能性があります。

ファイル名と属性のテキストファイルインデックスを保持するだけで、このプロセスを1桁(!)高速化するのが簡単だったとしたら、存在するすべてのファイルシステムとオペレーティングシステムがまさにそれを実行すると思いませんか?

とは言うものの、もちろん、特定のクエリの結果をキャッシュすると、パフォーマンスがわずかに向上する可能性があります。そして、予想通り、ファイルシステムとディスクキャッシングは、すべての最新のオペレーティングシステムとファイルシステムの基本的な部分です。

しかし、あなたが尋ねたように、あなたの質問には明確な答えがあります:いいえ。一般的なケースでは、再実装が1桁速くなることはありませんos.walk。キャッシュを使用することで、より優れた償却ランタイムを取得できる場合がありますが、プロファイリングにキャッシュを構築する作業を適切に含めると、桁違いに勝つことはありません。

于 2010-01-14T02:15:28.843 に答える
0

os.walkこれには、 (ディレクトリツリーを取得するため)とos.stat(ファイル情報を取得するため)の組み合わせを使用することをお勧めします。std-libを使用すると、すべてのプラットフォームで確実に機能し、うまく機能します。そして、何も索引付けする必要はありません。

他の人が述べているように、特にパスとパラメーターによって機能をすでに制限している場合は、ファイルシステムのインデックス作成と再インデックス作成を試みて、それほど多くを購入することはないと思います。

于 2010-01-13T20:33:16.043 に答える
0

私はPythonを初めて使用しますが、リスト内包表記を組み合わせて使用​​しています。読んだレポートによると、イテレーターとジェネレーターは悲鳴を上げるはずです。

class DirectoryIterator:
    def __init__(self, start_dir, pattern):
        self.directory = start_dir
        self.pattern = pattern

 def __iter__(self):
     [([DirectoryIterator(dir, self.pattern) for dir in dirnames], [(yield os.path.join(dirpath, name)) for name in filenames if re.search(self.pattern, name) ]) for dirpath, dirnames, filenames in os.walk(self.directory)]

 ###########

 for file_name in DirectoryIterator(".", "\.py$"): print file_name
于 2010-01-13T22:21:11.037 に答える