サーチ…


備考

Python開発者は、 threadingmultiprocessing間のAPIが類似しているため、プログラマにとって2つの変種の切り替えが簡単になりました。

スレッドモジュール

from __future__ import print_function
import threading
def counter(count):
    while count > 0:
        print("Count value", count)
        count -= 1
    return

t1 = threading.Thread(target=countdown,args=(10,))
t1.start()
t2 = threading.Thread(target=countdown,args=(20,))
t2.start()

I L OCKをnterpreter GIL、またはGのローブとして知られるものを使用するので、このようなCPythonのようなパイソンの特定の実装では、真の並列処理は、スレッドを使用して達成されません。

Pythonの並行処理の優れた概要を以下に示します。

David BeazleyによるPythonの同時実行性(YouTube)

マルチプロセッシングモジュール

from __future__ import print_function
import multiprocessing


def countdown(count):
    while count > 0:
        print("Count value", count)
        count -= 1
    return

if __name__ == "__main__":
    p1 = multiprocessing.Process(target=countdown, args=(10,))
    p1.start()

    p2 = multiprocessing.Process(target=countdown, args=(20,))
    p2.start()

    p1.join()
    p2.join()

ここでは、各機能は新しいプロセスで実行されます。 Python VMの新しいインスタンスがコードを実行しているので、 GILは存在せず、複数のコアで並列処理が実行されます。

Process.startメソッドは、この新しいプロセスを起動し、引数argsを使用してtarget引数で渡された関数を実行します。 Process.joinメソッドは、プロセスp1p2実行の終了を待ちます。

新しいプロセスは、パイソンのバージョンとコードが例えば実行されているplateformに応じて異なる起動されます:

  • Windowsは新しいプロセスを作成するためにspawnを使用します。
  • UNIXシステムと3.3より前のバージョンでは、 forkを使用してプロセスが作成されます。
    このメソッドはforkのPOSIX使用法を尊重しないため、特に他のマルチプロセッシングライブラリと相互作用するときに予期しない動作につながることに注意してください。
  • UNIXシステムとバージョン3.4以降では、プログラムの最初にmultiprocessing.set_start_methodを使用してforkforkserverまたはspawnいずれかを使って新しいプロセスを開始することができます。 forkserverspawnメソッドはforkよりも遅くなりますが、予期しない動作を避けます。

POSIX forkの使用法

マルチスレッドプログラムのfork後、execveを呼び出すまで安全にasync-signal-safe関数だけを安全に呼び出すことができます。
参照

forkを使用すると、現在のすべてのmutexに対して全く同じ状態で新しいプロセスが起動されますが、 MainThreadだけがMainThreadされます。それがレースの条件などにつながる可能性があるので、これは安全ではありません。

  • MainThreadLockを使用し、それをある時点でロックしようとしている他のスレッドに渡すとします。 fork同時に発生すると、新しいプロセスはロックされたロックから開始します。ロックされたロックは、この新しいプロセスに2番目のスレッドが存在しないため解放されません。

実のところ、この種の動作は純粋なPythonではmultiprocessingが適切に処理するためには起こらないはずですが、他のライブラリとやりとりしている場合、この種の動作が起こり、システムがクラッシュすることがあります。

マルチプロセッシングプロセス間でデータを渡す

データは2つのスレッド間で処理されるときに敏感なので(競合状態を引き起こして同時読み取りと同時書き込みが競合する可能性があると考えます)、スレッド間でデータのやりとりを容易にするために一意のオブジェクトが作成されました。本当のアトミック操作はすべてスレッド間で使用できますが、常にQueueに固執することは常に安全です。

import multiprocessing
import queue
my_Queue=multiprocessing.Queue() 
#Creates a queue with an undefined maximum size
#this can be dangerous as the queue becomes increasingly large
#it will take a long time to copy data to/from each read/write thread

大部分の人は、キューを使用するときは、空のデータを使用するのではなく、try:except:ブロックにキューのデータを置くことを推奨します。ただし、スキャンサイクルをスキップするかどうかは関係ありません(データがqueue.Empty==Truequeue.Empty==False状態を反転している間にキューに置くことができます) Iftryブロックと呼ばれるもので書き込みアクセスを行うことができます。なぜなら、 'if'ステートメントは例外をキャッチするよりも技術的に優れているからです。

import multiprocessing
import queue
'''Import necessary Python standard libraries, multiprocessing for classes and queue for the queue exceptions it provides'''
def Queue_Iftry_Get(get_queue, default=None, use_default=False, func=None, use_func=False):
    '''This global method for the Iftry block is provided for it's reuse and 
standard functionality, the if also saves on performance as opposed to catching
 the exception, which is expencive.
        It also allows the user to specify a function for the outgoing data to use,
 and a default value to return if the function cannot return the value from the queue'''
        if get_queue.empty():
            if use_default:
                return default
        else:
            try:
                value = get_queue.get_nowait()
            except queue.Empty:
                if use_default:
                    return default
            else:
                if use_func:
                    return func(value)
                else:
                    return value
    def Queue_Iftry_Put(put_queue, value):
        '''This global method for the Iftry block is provided because of its reuse 
and 
standard functionality, the If also saves on performance as opposed to catching
 the exception, which is expensive.
        Return True if placing value in the queue was successful. Otherwise, false'''
        if put_queue.full():
            return False
        else:
            try:
                put_queue.put_nowait(value)
            except queue.Full:
                return False
            else:
                return True


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow