[メモ]python multiprocessingモジュール


現在、ますます多くのコンピュータプログラムがマルチプロセス、マルチスレッドを採用しています.C++、Javaはマルチプロセスマルチスレッドモジュールを提供しており、pythonも例外ではありません.pythonはマルチプロセスの面でmultiprocessingモジュールを提供している.
サブプロセスの作成
import os
import multiprocessing as mp
def run_proc(name):
    print("run child process %s (%s)"%(name,os.getpid()))
if __name__ == '__main__':
    print("Parent process %s." % os.getpid())
    p = mp.Process(target = run_proc,args=('test',))
    print("Child process will start.")
    p.start()

    p.join()
    print("Child process end.")

上記のコードを実行すると、次の結果が得られます.
Parent process 51908. Child process will start. run child process test (51908) Child process end.
サブプロセスの作成には、関数とパラメータが必要です.サブプロセスのstart()メソッドは、サブプロセスを開始します.join()メソッドは、通常、プロセス間の同期に使用されるサブプロセスが終了してから実行を続行するのを待つことができます.
pool
サブスレッドが多い場合はスレッドプールを使用できます
from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')

プロセスプールのインスタンスはPool()によって作成され、パラメータはプロセスプールがサブプロセスを収容する個数であり、デフォルト値はコンピュータのcpuコア数であり、cpu_count()関数の戻り値は同じです.Poolインスタンスを作成すると、プロセスプールの関数apply_によってサブプロセスを直接プロセスプールに追加できます.async()は、関数名と対応するパラメータを含む上で作成したサブプロセスと同じパラメータを担当します.プロセスプールにサブプロセスを投げ捨てた後、プロセスプールを閉じることを忘れないでください.close()関数を使用して、プロセスプールを閉じます.これにより、他のサブプロセスが追加されません.プロセスプールインスタンスにはjoin()関数を使用します.これは、プロセスプール内のプロセスの実行が完了するまで待つことを目的としています.joinの前にcloseプロセスプールがない場合は、必ずエラーが表示されます.その結果,タスク0,1,2,3が先に実行され,プロセスプールは4つの位置しかないため,タスク0,1,2,3がほぼ同時に実行された.これは、Poolのデフォルトサイズが私のパソコンで4なので、最大4つのプロセスを同時に実行することができます.これはPoolが意図的に設計した制限であり、オペレーティングシステムの制限ではない.タスクを4つに変更すれば、待っている5番目のタスクは見えなくなります.
サブプロセスsubprocess
サブプロセスは、親プロセスによって作成されるプロセスです.サブプロセスを作成した後、サブプロセスに出力するパラメータを入力します.次の例では、サブプロセスを用いるpythonを得る.orgサイト情報のプロセス.
import subprocess
print("nslookup www.python.org")
r = subprocess.call(['nslookup','www.python.org'])

実行結果は、サーバ:dns.xxx.edu.cn Address: 10.0.0.10
非権威応答:名前:python.map.fastly.net Address: 103.245.222.223 Aliases: www.python.org
サブプロセスにさらにパラメータが必要な場合は、communicate()関数を使用して操作することもできます.communicateを行う前にsubprocessを作成する.Popen()インスタンス.communicateの役割は、Interact with process:Send data to stdinである.Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be bytes to be sent to the child process, or None, if no data should be sent to the child.
import subprocess
print('nslookup')
p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'set q=mx
python.org
exit
'
) print(output.decode('gbk')) print('Exit code:', p.returncode)

実行結果は、デフォルトのサーバ:dns.xxx.edu.cn Address: 10.0.0.10
>>サーバ:dns.xxx.edu.cn Address: 10.0.0.10
python.org MX preference = 50, mail exchanger = mail.python.org
python.org nameserver = ns2.p11.dynect.net python.org nameserver = ns4.p11.dynect.net python.org nameserver = ns1.p11.dynect.net python.org nameserver = ns3.p11.dynect.net mail.python.org internet address = 82.94.164.166 mail.python.org AAAA IPv6 address = 2001:888:2000:d::a6 ns3.p11.dynect.net internet address = 208.78.71.11 ns1.p11.dynect.net internet address = 208.78.70.11 ns4.p11.dynect.net internet address = 204.13.251.11 ns2.p11.dynect.net internet address = 204.13.250.11 > Exit code: 0
プロセス間通信
プロセス間でタスクを処理する場合は、情報、すなわち通信を共有する必要があります.pythonのmultiprocessモジュールはQueue,Pipesなどの通信動作を提供する.次の例ではQueueを使用してデータを転送します.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import multiprocessing as mp
import time, random, os


def write(que):
    """ @parameter: que, a Queue Objct """
    print('Process %s to write' % (os.getpid(),))
    for val in ['a','b','c']:
        print('putting %s in que'%(val,))
        que.put(val)
        time.sleep(1)

def read(que):
    """ @parameter: que, a Queue Objct """
    print('Process %s to read' % (os.getpid(),))
    while True:
        value = que.get(block=True) # reading and writing cannot
                                    # happen simutaneously
        print('Get %s from queue.' % value)


if __name__ == "__main__":
    que = mp.Queue()
    pw = mp.Process(target=write, args=(que,))
    pr = mp.Process(target=read, args=(que,))

    pw.start()
    pr.start()

    pw.join() # wairing for the end of pw
    pr.terminate()

実行結果は以下の通りである:Process 32520 to read Process 34836 to write putting a in que Get a from queue.putting b in que Get b from queue. putting c in que Get c from queue.