5

サーバー上に存在するファイルがほとんどなく、パフォーマンスを向上させるためにマルチスレッドプロセスを実装しようとしています。チュートリアルを読みましたが、実装に関する質問がいくつかあります。

これがファイルです、

filelistread = ['h:\\file1.txt', \
                'h:\\file2.txt', \
                'h:\\file3.txt', \
                'h:\\file4.txt']

filelistwrte = ['h:\\file1-out.txt','h:\\file2-out.txt','h:\\file3-out.txt','h:\\file4-out.txt']


def workermethod(inpfile, outfile):
    f1 = open(inpfile,'r')
    f2 = open(outfile,'w')
    x = f1.readlines()
    for each in x:
        f2.write(each)
    f1.close()
    f2.close()

スレッドクラスとキューを使用して実装するにはどうすればよいですか?

以下のクラスから始めましたが、inpfileとoutputfileをrunメソッドに渡す方法がわかりません。任意の入力を歓迎します。

class ThreadUrl(threading.Thread):
    def __init__(self,queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def run(self):
        while True:
            item = self.queue.get()
4

1 に答える 1

29

2 つの異なるソリューションを混同しています。

ファイルごとに専用のワーカー スレッドを作成する場合は、何のキューも必要ありません。スレッドプールとファイルのキューを作成する場合は、andをメソッドに渡したくありません。それらをキューの各ジョブに入れたいとします。inpfileoutfilerun

2つの中からどのように選択しますか?最初のほうが明らかに単純ですが、たとえば、コピーするファイルが 1000 個ある場合、最終的に 1000 個のスレッドを作成することになります。これは、作成したいよりも多くのスレッドであり、並列コピーの数よりもはるかに多くのスレッドです。 OSが処理できるようになります。スレッド プールを使用すると、たとえば 8 つのスレッドを作成し、1000 個のジョブをキューに入れることができます。ジョブは必要に応じてスレッドに分散されるため、一度に 8 つのジョブが実行されます。

各ファイル専用のワーカー スレッドであるソリューション 1 から始めましょう。

まず、サブクラス化と結婚していない場合Thread、ここでそうする理由はまったくありません。target関数とargsタプルをデフォルトのコンストラクターに渡すことができます。その後、runメソッドはtarget(*args)必要に応じて正確に実行します。そう:

t = threading.Thread(target=workermethod, args=(inpfile, outfile))

それだけです。各スレッドが実行されると、呼び出しworkermethod(inpfile, outfile)てから終了します。

ただし、何らかの理由でサブクラス化たい場合は可能です。構築時に and を渡すことができます。メソッドThreadは、パラメーターを受け取る代わりにandを使用するように変更されたものになります。このような:inpfileoutfilerunworkermethodself.inpfileself.outfile

class ThreadUrl(threading.Thread):
    def __init__(self, inpfile, outfile):
        threading.Thread.__init__(self)
        self.inpfile, self.outfile = inpfile, outfile

    def run(self):
        f1 = open(self.inpfile,'r')
        f2 = open(self.outfile,'w')
        x = f1.readlines()
        for each in x:
            f2.write(each)
        f1.close()
        f2.close()

いずれにせよ、非常に古いバージョンの Python を扱う必要がない限り、明示的な and の代わりにステートメントを使用し、(不必要にファイル全体をメモリに読み込む) を取り除くwithことをお勧めします。openclosereadlines

    def run(self):
        with open(self.inpfile,'r') as f1, open(self.outfile,'w') as f2:
            for line in f1:
                f2.write(line)

次に、解決策 2 に進みます: スレッドプールとキュー。

ここでも、サブクラスは必要ありません。物事を行う 2 つの方法の違いは、ソリューション 1 と同じです。ただし、開始したサブクラスの設計に固執すると、次のようなものが必要になります。

class ThreadUrl(threading.Thread):
    def __init__(self,queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def run(self):
        while True:
            inpfile, outfile = self.queue.get()
            workermethod(inpfile, outfile)

次に、単一のスレッドqueueをすべてのスレッドに渡してスレッドを開始します。

q = queue.Queue
threadpool = [ThreadUrl(q) for i in range(poolsize)]

そして、次のようなジョブを送信します。

q.put((inpfile, outfile))

スレッドプールで本格的な作業を行う場合は、自分で何かをコーディングするのではなく、堅牢で柔軟性があり、シンプルで最適化された実装を使用することを検討することをお勧めします。たとえば、ジョブをキャンセルしたり、キューを適切にシャットダウンしたり、スレッドを 1 つずつ結合する代わりにプール全体に結合したり、バッチ処理やスマートな負荷分散を実行したりしたい場合があります。

Python 3 を使用している場合は、 standard-library を確認する必要がありますThreadPoolExecutorFuturePython 2 に行き詰まっている場合、またはsがわからない場合は、モジュールThreadPool内に隠されているクラスを確認することをお勧めします。multiprocessingこれらの両方には、マルチスレッドからマルチプロセッシングへの切り替えが簡単であるという利点があります (たとえば、IO と共に並列化する必要がある CPU バウンドの作業があることが判明した場合)。PyPI を検索することもできます。他にも優れた実装が複数見つかります。

queue補足として、モジュール名をシャドウするため、 queue を呼び出したくありません。workermethodまた、実際にはメソッドではなくフリー関数であると呼ばれるものがあると、少し混乱します。

最後に、ファイルをコピーするだけなら、おそらくテキスト モードで読んだり、行単位で読みたいとは思わないでしょう。実際、自分で実装したいとは思わないでしょう。から適切なコピー機能を使用するだけshutilです。上記の方法のいずれかで非常に簡単にそれを行うことができます。たとえば、これの代わりに:

t = threading.Thread(target=workermethod, args=(inpfile, outfile))

これを行う:

t = threading.Thread(target=shutil.copyfile, args=(inpfile, outfile))

実際、プログラム全体を次のように置き換えることができるようです。

threads = [threading.Thread(target=shutil.copyfile, args=(inpfile, outfile))
           for (inpfile, outfile) in zip(filelistread, filelistwrte)]
for thread in threads:
    thread.start()
for thread in threads:
    thread.join()
于 2013-01-02T23:19:38.190 に答える