ホームページ  >  記事  >  バックエンド開発  >  Pythonマルチプロセスプログラミングの深い理解

Pythonマルチプロセスプログラミングの深い理解

WBOY
WBOYオリジナル
2016-06-16 08:47:521250ブラウズ

1. Python マルチプロセス プログラミングの背景

Python のマルチプロセスの最大の利点は、マルチコア CPU のリソースを最大限に活用できることです。Python のマルチスレッドとは異なり、GIL の制限があり、マルチプロセスでのみ CPU 割り当てを実行できます。 Pythonでは、すべてに適しています。場合によっては、基本的にマルチスレッドを使用でき、その後、基本的にマルチプロセスを使用できます。

マルチプロセス プログラミングを行う場合、マルチスレッド パッケージのスレッドには、スレッドを作成し、スレッドを開始するための 3 つのメソッドがあります。実際、マルチプロセス プログラミングにはプロセス クラス Process があり、これは集中メソッドを使用して使用することもできます。マルチスレッドでは、リストなどのメモリ内のデータを直接共有できます。 -プロセスでは、メモリ データを共有できないため、共有データを処理するには別のデータ構造を使用する必要があります。マルチスレッドでは、データ共有によりデータの正確性が保証される必要がありますが、マルチプロセスではロックが発生することはほとんどありません。プロセスが共有されていないため、メモリ情報については、マルチプロセスでは、プロセス間の対話データが特別なデータ構造を通過する必要があり、主な内容は次のとおりです。

2. マルチプロセスクラス Process

マルチプロセス クラス Process とマルチスレッド クラス Thread には同様のメソッドがあります。詳細については、次のコードを参照してください。

#!/usr/bin/env python

from multiprocessing import Process
import os
import time

def func(name):
  print 'start a process'
  time.sleep(3)
  print 'the process parent id :',os.getppid()
  print 'the process id is :',os.getpid()

if __name__ =='__main__':
  processes = []
  for i in range(2):
    p = Process(target=func,args=(i,))
    processes.append(p)
  for i in processes:
    i.start()
  print 'start all process'
  for i in processes:
    i.join()
    #pass
  print 'all sub process is done!'
上記の例でわかるように、マルチプロセスとマルチスレッドの API インターフェイスは同じです。これは、プロセスの作成、実行の開始、プロセスの完了を待つ参加を示しています。終わり。

実行する必要のある関数にはプロセスのidとpidが出力されており、親プロセスと子プロセスのid番号が確認できます。linuでは主にプロセスがforkされていて確認できます。プロセスを作成するときに、親プロセスと子プロセスの ID 番号を問い合わせます。ただし、マルチスレッドではスレッド ID が見つかりません。

オペレーティング システムで ID をクエリする場合は、pstree を使用してクリアするのが最善です:
start all process
start a process
start a process

the process parent id : 8036
the process parent id : 8036
the process id is : 8037
the process id is : 8038
all sub process is done!

実行時に、join ステートメントがない場合、メイン プロセスはサブプロセスの終了を待たずに実行を継続し、サブプロセスの実行を待つことがわかります。

├─sshd(1508)─┬─sshd(2259)───bash(2261)───python(7520)─┬─python(7521)
    │      │                    ├─python(7522)
    │      │                    ├─python(7523)
    │      │                    ├─python(7524)
    │      │                    ├─python(7525)
    │      │                    ├─python(7526)
    │      │                    ├─python(7527)
    │      │                    ├─python(7528)
    │      │                    ├─python(7529)
    │      │                    ├─python(7530)
    │      │                    ├─python(7531)
    │      │                    └─python(7532)
複数のプロセスを使用する場合、複数のプロセスの戻り値を取得するにはどうすればよいですか?次に、次のコードを書きました:

メインプロセスで子プロセスの戻り値を取得するために結果から値を返そうとしましたが、結果がありませんでした。プロセス内でプロセス間でメモリが共有されていないのではないかと思いました。したがって、リストを使用します。データを保存することは明らかに不可能です。したがって、上記のコードはプロセスを実行するだけであり、プロセスの戻り値を取得することはできません。スレッドに変更すると、価値のある戻り値を取得できます。
#!/usr/bin/env python

import multiprocessing

class MyProcess(multiprocessing.Process):
  def __init__(self,name,func,args):
    super(MyProcess,self).__init__()
    self.name = name
    self.func = func
    self.args = args
    self.res = ''

  def run(self):
    self.res = self.func(*self.args)
    print self.name
    print self.res
    return (self.res,'kel')

def func(name):
  print 'start process...'
  return name.upper()

if __name__ == '__main__':
  processes = []
  result = []
  for i in range(3):
    p = MyProcess('process',func,('kel',))
    processes.append(p)
  for i in processes:
    i.start()
  for i in processes:
    i.join()
  for i in processes:
    result.append(i.res)
  for i in result:
    print i

3. プロセス間のインタラクション キュー

プロセス間で対話する場合、最初はマルチスレッドで同じキュー構造を使用できますが、複数のプロセスではマルチプロセスでキューを使用する必要があります。コードは次のとおりです。

実際、これは上記の例を改良したもので、プロセス間でデータを交換するという目的を達成するために、主に Queue を使用してデータを保存します。
#!/usr/bin/env python

import multiprocessing

class MyProcess(multiprocessing.Process):
  def __init__(self,name,func,args):
    super(MyProcess,self).__init__()
    self.name = name
    self.func = func
    self.args = args
    self.res = ''

  def run(self):
    self.res = self.func(*self.args)

def func(name,q):
  print 'start process...'
  q.put(name.upper())

if __name__ == '__main__':
  processes = []
  q = multiprocessing.Queue()
  for i in range(3):
    p = MyProcess('process',func,('kel',q))
    processes.append(p)
  for i in processes:
    i.start()
  for i in processes:
    i.join()
  while q.qsize() > 0:
    print q.get()
Queueを使う場合、実際にソケットを使うのはsendを送信してrecvを受信するだけなので、という感じです。

データ対話を実行するとき、親プロセスは実際にはすべての子プロセスと対話します。ただし、たとえば、各プロセスがデータを取得するためにキューに移動する場合を除き、基本的にすべての子プロセス間に対話はありません。この時点でロックを考慮する必要があります。そうしないと、データが混乱する可能性があります。

4. プロセス間の対話 Pipe

パイプはプロセス間でデータを交換する場合にも使用できます。コードは次のとおりです。

上記のコードでは、Pipe で返される 2 つのソケットは主にデータの送受信に使用され、親プロセスではparent_conn が使用され、子プロセスでは child_conn がデータの送信メソッドとして使用されます。親プロセスのメソッドrecv

の送信と受信
最も良い点は、送受信の回数が明確にわかることですが、何か異常がある場合は、パイプが使用できない可能性があります。
#!/usr/bin/env python

import multiprocessing

class MyProcess(multiprocessing.Process):
  def __init__(self,name,func,args):
    super(MyProcess,self).__init__()
    self.name = name
    self.func = func
    self.args = args
    self.res = ''

  def run(self):
    self.res = self.func(*self.args)

def func(name,q):
  print 'start process...'
  child_conn.send(name.upper())

if __name__ == '__main__':
  processes = []
  parent_conn,child_conn = multiprocessing.Pipe()
  for i in range(3):
    p = MyProcess('process',func,('kel',child_conn))
    processes.append(p)
  for i in processes:
    i.start()
  for i in processes:
    i.join()
  for i in processes:
    print parent_conn.recv()

5. プロセスプール pool

実際、複数のプロセスを使用する場合、マルチスレッドにはプールがありませんので、プールを使用するのが最も便利だと感じます。 プールを使用する場合、毎回プロセスの数を制限できます。つまり、残りのプロセスはキューに入れられ、設定された数のプロセスのみが実行されます。デフォルトでは、プロセスの数は CPU の数になります。これは multiprocessing.cpu_count() に基づく結果です。

在poo中,有两个方法,一个是map一个是imap,其实这两方法超级方便,在执行结束之后,可以得到每个进程的返回结果,但是缺点就是每次的时候,只能有一个参数,也就是在执行的函数中,最多是只有一个参数的,否则,需要使用组合参数的方法,代码如下所示:

#!/usr/bin/env python

import multiprocessing

def func(name):
  print 'start process'
  return name.upper()

if __name__ == '__main__':
  p = multiprocessing.Pool(5)
  print p.map(func,['kel','smile'])
  for i in p.imap(func,['kel','smile']):
    print i

在使用map的时候,直接返回的一个是一个list,从而这个list也就是函数执行的结果,而在imap中,返回的是一个由结果组成的迭代器,如果需要使用多个参数的话,那么估计需要*args,从而使用参数args。

在使用apply.async的时候,可以直接使用多个参数,如下所示:

#!/usr/bin/env python

import multiprocessing
import time
def func(name):
  print 'start process'
  time.sleep(2)
  return name.upper()

if __name__ == '__main__':
  results = []
  p = multiprocessing.Pool(5)
  for i in range(7):
    res = p.apply_async(func,args=('kel',))
    results.append(res)
  for i in results:
    print i.get(2.1)

在进行得到各个结果的时候,注意使用了一个list来进行append,要不然在得到结果get的时候会阻塞进程,从而将多进程编程了单进程,从而使用了一个list来存放相关的结果,在进行得到get数据的时候,可以设置超时时间,也就是get(timeout=5),这种设置。

总结:

在进行多进程编程的时候,注意进程之间的交互,在执行函数之后,如何得到执行函数的结果,可以使用特殊的数据结构,例如Queue或者Pipe或者其他,在使用pool的时候,可以直接得到结果,map和imap都是直接得到一个list和可迭代对象,而apply_async得到的结果需要用一个list装起来,然后得到每个结果。

以上这篇深入理解python多进程编程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

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