ホームページ >バックエンド開発 >Python チュートリアル >Python でのプロセス管理: 並列プログラミングの基礎

Python でのプロセス管理: 並列プログラミングの基礎

Patricia Arquette
Patricia Arquetteオリジナル
2025-01-03 09:52:40145ブラウズ

Process Management in Python: Fundamentals of Parallel Programming

並列プログラミングは、プログラムが複数のプロセッサまたはコアで複数のタスクを同時に実行できるようにするプログラミング モデルです。このモデルは、プロセッサ リソースをより効率的に使用し、処理時間を短縮し、パフォーマンスを向上させることを目的としています。

並列プログラミングを画像で説明すると、問題があると想像できます。並列処理を開始する前に、この問題を小さな部分に分割します。これらのサブパートは互いに独立しており、お互いについて何も知らないと仮定します。各サブ問題は、より小さなタスクまたは指示に変換されます。これらのタスクは、並行作業に適した方法で編成されています。たとえば、データセットに対して同じ操作を実行するために多くの命令を作成できます。これらのタスクはさまざまなプロセッサに分散されます。各プロセッサは、割り当てられた命令を独立して並行して処理します。このプロセスにより、総処理時間が大幅に短縮され、リソースをより効率的に使用できるようになります。

Python では、並列プログラミング用のツールとモジュールがいくつか提供されています。

**マルチプロセッシング
**これにより、プログラムは複数のプロセスを同時に実行できるようになり、真の並列処理を活用できるようになります。マルチプロセッシング モジュールは GIL (グローバル インタープリター ロック) の制限を克服し、マルチコア プロセッサーで最大限のパフォーマンスを実現できます。

グローバル インタプリタ ロック (GIL) は、CPython と呼ばれる Python の一般的な実装で使用されるメカニズムです。 GIL では、一度に 1 つのスレッドのみが Python バイトコードを実行できます。これは、Python でマルチスレッドが使用される場合に真の並列処理を制限する構造です。

*正方形と立方体の計算例
*

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

マルチプロセッシングが必要な理由 マルチプロセッシングの必要性は、料理人やキッチンに例えて説明できます。料理人がキッチンで一人で調理することを単一プロセス プログラムと考えることができます。複数の料理人が同じキッチンで一緒に作業することを、マルチプロセッシングに例えることができます。

単一プロセス - 単一調理

キッチンには調理人が 1 人だけです。この料理人は前菜、メインコース、デザートの 3 つの異なる料理を作ります。各料理は順番に作られます:
彼はスターターを準備して完成させます。
彼はメインコースに進み、それを終了します。
最後にデザートを作ります。
問題:

料理人がどんなに早くても、交代で調理するため、キッチンでの時間が無駄になります。
3 つの異なる料理を同時に調理する必要がある場合は、時間が長くなります。
マルチプロセッシング - 多くのクック

次に、同じキッチンに 3 人の料理人がいると想像してください。それぞれが異なる料理を準備しています:
一人の料理人がスターターを作ります。
2 番目の料理人がメインコースを準備します。
3人目の料理人がデザートを作ります。
利点:

3 つの料理が同時に作られるため、合計時間が大幅に短縮されます。
各クックは独立して独自の作業を実行し、他のクックの影響を受けません。
Python でプロセス間でデータを共有する
Python では、multiprocessing モジュールを使用して、異なるプロセス間でデータを共有することができます。ただし、各プロセスは独自のメモリ空間を使用します。したがって、プロセス間でデータを共有するために特別なメカニズムが使用されます。

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

コードサンプルを調べると、結果リストが空であることがわかります。この主な理由は、マルチプロセッシングで作成されたプロセスがメイン プロセスから独立した独自のメモリ空間で動作するためです。この独立性のため、子プロセスで行われた変更は、メイン プロセスの変数に直接反映されません。

Python には、データを共有するための次のメソッドが用意されています。

**1.共有メモリ
**Value オブジェクトと Array オブジェクトは、操作間でデータを共有するために使用されます。
値: 単一のデータ型 (数値など) を共有します。
配列: データの配列を共有するために使用されます。

import multiprocessing

result = []

def square_of_list(mylist):
    for num in mylist:
        result.append(num**2)
    return result

mylist= [1,3,4,5]

p1 = multiprocessing.Process(target=square_of_list,args=(mylist,))
p1.start()
p1.join()

print(result) # [] Boş Liste

**2.キュー
**FIFO (先入れ先出し) 構造を使用してプロセス間でデータを転送します。
multiprocessing.Queue を使用すると、複数のプロセスがデータを送受信できるようになります。

from multiprocessing import Process, Value

def increment(shared_value):
    for _ in range(1000):
        shared_value.value += 1  

if __name__ == "__main__":
    shared_value = Value('i', 0)  
    processes = [Process(target=increment, args=(shared_value,)) for _ in range(5)]

    for p in processes:
        p.start()
    for p in processes:
        p.join()

    print(f"Sonuç: {shared_value.value}")

**3.パイプ
**multiprocessing.Pipe は、2 つのプロセス間の双方向のデータ転送を提供します。
データの送信と受信の両方に使用できます。

from multiprocessing import Process, Queue

def producer(queue):
    for i in range(5):
        queue.put(i)  # Kuyruğa veri ekle
        print(f"Üretildi: {i}")

def consumer(queue):
    while not queue.empty():
        item = queue.get()  
        print(f"Tüketildi: {item}")

if __name__ == "__main__":
    queue = Queue()

    producer_process = Process(target=producer, args=(queue,))
    consumer_process = Process(target=consumer, args=(queue,))

    producer_process.start()
    producer_process.join()

    consumer_process.start()
    consumer_process.join()

*プロセス間のパディング
*
「プロセス間のパディング」は、プロセス メモリの編成や、複数のプロセス間で共有されるデータにアクセスする際のデータの配置や衝突の問題を回避するためによく使用されます。

この概念は、キャッシュラインのフォールス シェアリングなどの場合に特に重要です。複数のプロセスが同時に共有メモリを使用しようとすると、誤った共有によりパフォーマンスの低下が発生する可能性があります。これは、最新のプロセッサでのキャッシュラインの共有が原因です。

**プロセス間の同期
**Python のマルチプロセッシング モジュールを使用すると、複数のプロセスを同時に実行できます。ただし、複数のプロセスが同じデータにアクセスする必要がある場合は、同期を使用することが重要です。これは、データの一貫性を確保し、競合状態などの問題を回避するために必要です。

from multiprocessing import Process, Pipe

def send_data(conn):
    conn.send([1, 2, 3, 4])  
    conn.close()

if __name__ == "__main__":
    parent_conn, child_conn = Pipe()  

    process = Process(target=send_data, args=(child_conn,))
    process.start()

    print(f"Alınan veri: {parent_conn.recv()}")  # Veri al
    process.join()

ロックにより、一度に 1 つのプロセスのみが共有データにアクセスできます。
ロックを使用しているプロセスが完了する前に、他のプロセスが待機します。

**マルチスレッド

マルチスレッドは、プログラムで複数のスレッドを同時に実行できるようにする並列プログラミング モデルです。スレッドは、同じプロセス内で実行される小さな独立したコード単位であり、リソースを共有することでより高速かつ効率的な処理を目指します。
Python では、マルチスレッド アプリケーションの開発にスレッド モジュールが使用されます。ただし、Python の Global Interpreter Lock (GIL) メカニズムにより、マルチスレッドでは CPU に依存するタスクのパフォーマンスが制限されます。したがって、一般に、I/O バウンドのタスクではマルチスレッドが推奨されます。

スレッドはプログラム内の一連の命令です。

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

**スレッド同期
**スレッド同期は、複数のスレッドが同じリソースに同時にアクセスするときに、データの一貫性と順序を確保するために使用される技術です。 Python では、スレッド モジュールは同期用のツールをいくつか提供します。

**スレッド同期が必要な理由
**競合状況:

2 つ以上のスレッドが共有リソースに同時にアクセスすると、データの不整合が発生する可能性があります。
たとえば、あるスレッドがデータを読み取りながら、別のスレッドが同じデータを更新する場合があります。
*データの一貫性:
*

共有リソースが正しく更新されるようにするには、スレッド間の調整が必要です。
Python での同期ツールの例
**1.ロック
**スレッドはロックを取得すると、他のスレッドが同じリソースにアクセスできるようになる前に、ロックが解放されるのを待ちます。

import multiprocessing

result = []

def square_of_list(mylist):
    for num in mylist:
        result.append(num**2)
    return result

mylist= [1,3,4,5]

p1 = multiprocessing.Process(target=square_of_list,args=(mylist,))
p1.start()
p1.join()

print(result) # [] Boş Liste

2-イベント

from multiprocessing import Process, Value

def increment(shared_value):
    for _ in range(1000):
        shared_value.value += 1  

if __name__ == "__main__":
    shared_value = Value('i', 0)  
    processes = [Process(target=increment, args=(shared_value,)) for _ in range(5)]

    for p in processes:
        p.start()
    for p in processes:
        p.join()

    print(f"Sonuç: {shared_value.value}")

**結論:
**スレッドの同期は、スレッドが共有リソースにアクセスするときにデータの不整合を防ぐために重要です。 Python では、Lock、RLock、Semaphore、Event、Condition などのツールが、同期のニーズに応じた効果的なソリューションを提供します。どのツールを使用するかは、アプリケーションのニーズと同期要件によって異なります。

以上がPython でのプロセス管理: 並列プログラミングの基礎の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:PyTorch のサブ次の記事:PyTorch のサブ