Python パフォーマンス最適化の例の演習 3 - マルチプロセス

1. プロセスの作成と管理

The multiprocessing module is used, , common attributes and methods of the Python Process class. その他のメソッドについては、公式ドキュメントfrom multiprocessing import Processのリファレンス セクションを参照してください

プロパティまたはメソッド名 関数
始める() 子スレッドを開始するのと同様に、新しく作成されたプロセスも手動で開始する必要があります. このメソッドの機能は、新しく作成されたスレッドを開始することです.
走る() プロセスを作成する 2 番目の方法を使用する必要があります. 継承されたクラスは、新しいプロセスによって実行されるコードを含むメソッドを書き換える必要があります.
join([タイムアウト]) スレッド クラスの join() メソッドの使用と同様に、その機能は、マルチプロセス実行のプロセスで、join() メソッドを呼び出すプロセスが実行を終了する (または指定されたタイムアウトを実行する) まで、他のプロセスを待機する必要があることです。 time) 実行を続行する前。
生きている() プロセスが生きているかどうかを判断し、生き残っている場合は True を返し、そうでない場合は False を返します。
終了() プロセスを中断します。
名前 プロセスの名前を変更でき、プロセスの名前も取得できます。
デーモン デーモン スレッドと同様に、このプロパティを True に設定すると、新しく作成されたプロセスを「デーモン プロセス」として設定できます。
ピッド プロセスの ID 番号を返します。ほとんどのオペレーティング システムは、各プロセスに一意の ID 番号を割り当てます。
終了コード プロセスが実行中の場合は None、-N の場合はシグナル N で終了することを意味します。
認証キー プロセス認証。デフォルトは、os.urandom() によってランダムに生成された 32 文字の文字列です。このキーの目的は、ネットワーク接続を含む低レベルのプロセス間通信にセキュリティを提供することです。このような接続は、同じ認証を持っている場合にのみ成功します。

Windows システムで複数のプロセスを実行する場合は、Process をif __name__ == '__main__':下に配置してください。Python プログラム エントリ== ' main ' には、プログラミングの習慣よりも重要な機能 (マルチスレッド) があります。

1.1 Process クラスのインスタンスオブジェクト

(上表と以下のコードは、Python プロセスを作成するプロセスの詳細な説明 (2 つの方法)を参照しており、一部変更されています)

from multiprocessing import Process
import os

# 定义为进程方法传入的参数
my_tuple = ("http://c.biancheng.net/python/",
            "http://c.biancheng.net/shell/",
            "http://c.biancheng.net/java/")


# 定义一个函数,准备作为新进程的 target 参数,打印my_tuple中的信息
def action(name, *add):
    print("I am child, the pid is %d." % os.getpid())
    for arc in add:
        print("%s --当前进程%d" % (arc, os.getpid()))


if __name__ == '__main__':
    print("I am father, the pid is %d." % os.getpid())
    # 创建子进程,执行 action() 函数
    my_process = Process(target=action, args=("my_process进程", *my_tuple))
    # 启动子进程
    my_process.start()
    my_process.join()
    print("I am father, over")

プログラムの実行結果は次のとおりです。

I am father, the pid is 18968.
I am child, the pid is 18984.
http://c.biancheng.net/python/ --当前进程18984
http://c.biancheng.net/shell/ --当前进程18984
http://c.biancheng.net/java/ --当前进程18984
I am father, over

multiprocessing.Process を介してプロセスを作成および開始する場合、プログラムは最初に を判断する必要がありますif __name__=='__main__':。そうしないと、プログラムの実行時に例外がスローされます。

この実行方法は、Python でスレッドを実行するのと非常によく似ており、親プロセスの Process クラスのオブジェクトが 2 つの分岐を生成し、1 つの分岐が関数アクションでプログラムを実行し、もう 1 つの分岐が引き続き実行され、最終的には次のようになります。合併しました。

1.2 Process 継承クラスによるプロセスの作成

Process クラスのサブクラスを継承し、インスタンス オブジェクトを作成することで、新しいプロセスを作成することもできます。Process クラスから継承するサブクラスは、親クラスの run() メソッドをオーバーライドする必要があることに注意してください。

from multiprocessing import Process
import os


# 定义为进程方法传入的参数
my_tuple = ("http://c.biancheng.net/python/",
            "http://c.biancheng.net/shell/",
            "http://c.biancheng.net/java/")


# 自定义一个进程类,从Process继承
class My_Process(Process):
    def __init__(self, name, *add):
        super().__init__()
        self.name = name
        self.add = add

    def run(self):
        print(self.name)
        for arc in self.add:
            print("%s --当前进程%d" % (arc,os.getpid()))


if __name__ == '__main__':
    # 定义为进程方法传入的参数
    print("I am father, the pid is %d." % os.getpid())
    my_process = My_Process("my_process进程", *my_tuple)

    # 启动子进程
    my_process.start()   # 运行的就是My_Process中run方法中的内容

    my_process.join()
    print("I am father, over")

プログラムの実行結果は次のとおりです。

I am father, the pid is 1936.
my_process进程
http://c.biancheng.net/python/ --当前进程23288
http://c.biancheng.net/shell/ --当前进程23288
http://c.biancheng.net/java/ --当前进程23288
I am father, over

プロセス ID 番号を除いて、残りは同じです。

1.3 複数プロセスの作成と破棄

次のコードは、Python マルチプロセスを取得するための記事からの抜粋です (完全)

from multiprocessing import  Process


def fun1(idx):
    print('测试%d多进程' % idx)


if __name__ == '__main__':
    process_list = [Process(target=fun1, args=(x,)) for x in range(0, 5)]
    for p in process_list:
        p.start()

    for p in process_list:
        p.join()

    print('结束测试')

プログラムの実行結果は次のとおりです。

测试0多进程
测试1多进程
测试2多进程
测试3多进程
测试4多进程
结束测试

Process finished with exit code 0

上記のコードは、5 つの子プロセスを開始して関数を実行し、各プロセスをリストに追加してから、リサイクルのためにリストをトラバースします。

C 言語でのマルチプロセス プログラミングでは、プロセスのリサイクルに厳しい要件があり、プロセスをリサイクルする必要があります。そうしないと、システム メモリを占有するゾンビ プロセスになるため、フル機能のプロセス リサイクル関数 wait() と waitpid があります。 () . Python で現在発生しているリサイクルは、あまり良いコンテンツに遭遇していないため、最初に穴を掘ります。

1.4 プロセスの終了ステータス

from multiprocessing import Process
import time


def first():
    print("There is no problem here")


def second():
    raise RuntimeError("Error raised!")


def third():
    time.sleep(3)
    print("This process will be terminated")


if __name__ == '__main__':
    workers = [Process(target=first), Process(target=second), Process(target=third)]
    for w in workers:
        w.start()

    workers[-1].terminate()

    for w in workers:
        w.join()

    for w in workers:
        print(w.exitcode)

プログラムの実行結果は次のとおりです。

There is no problem here
Process Process-2:
Traceback (most recent call last):
  File "D:\Anaconda\envs\yolo_pytorch38\lib\multiprocessing\process.py", line 315, in _bootstrap
    self.run()
  File "D:\Anaconda\envs\yolo_pytorch38\lib\multiprocessing\process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "E:\Code\Yolo_related_code\yolov5-master-main\scripts\processes.py", line 10, in second
    raise RuntimeError("Error raised!")
RuntimeError: Error raised!
0
1
-15

プロセスが終了(または中断)すると、実行結果を示す数字である終了コード(exitcode)が生成されます。異なる番号は、プロセスが正常終了したか、異常終了したか、または別のプロセスによって中断されたかを示します。
具体的には、以下の 3 つの状況があります
。0 に等しい場合は正常終了、
0 より大きい場合は異常終了、
0 未満の場合は -1*exit_code シグナルによって別のプロセスによってプロセスが終了されたことを意味します。

1.5 プロセスの作成方法 spawn と fork

プロセスを作成しても速度が上がらない場合があり、元のプログラムが大きなライブラリを大量にインポートする必要がある場合、プロセス作成の特性上、代わりに速度が遅くなります。

Python マルチプロセスでは、プロセスを作成する方法として、spawn と fork の 2 つの方法を選択できます。ブランチの作成: fork は実行する子プロセスに直接コピーし、子プロセスにすべてのリソースのハンドルを継承させるため、作成速度は非常に高速ですが、より多くのメモリ リソースを消費します。分割作成: spawn は必要なリソース ハンドルのみを子プロセスに渡すため、作成速度はわずかに遅くなります。詳細な説明については、Stack OverFlow マルチプロセッシング フォークとスポーンを参照してください。

パフォーマンス最適化の悲しい旅を思い出してください [Flask+Gunicorn+pytorch+multi-process+thread pool、1 つの操作は虎のように激しい]

2. プロセス間通信

2.1 待ち行列(待ち行列)

Queue クラスは、スレッドセーフでプロセスセーフな先入れ先出し (FIFO、先入れ先出しの
データ交換メカニズム。

from multiprocessing import Process, Queue

def f(q):
    q.put([42, None, 'hello'])

if __name__ == '__main__':
    q = Queue()
    p = Process(target=f, args=(q,))
    p.start()
    print(q.get())    # prints "[42, None, 'hello']"
    p.join()

2.2 パイプ(パイプライン)

2.3 メモリ共有

3. プロセス プール

4.参考リンク

Python マルチプロセスを手に入れるための記事 (フル)
Python プロセス作成プロセスの詳細な説明 (2 つの方法)
これを強くお勧めします、このブロガーはそれを非常によく理解していますPython でマルチプロセスをエレガントに使用する
公式ドキュメント:マルチプロセッシング — プロセスベースの並列処理

おすすめ

転載: blog.csdn.net/weixin_42442319/article/details/127771972