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

Python でのマルチプロセス プログラミングを理解する

高洛峰
高洛峰オリジナル
2017-03-03 13:51:331235ブラウズ

次のエディターは、Python マルチプロセス プログラミングについての深い理解をもたらします。編集者はこれがとても良いと思ったので、参考として共有します。エディターをフォローして一緒に見てみましょう

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

Python におけるマルチプロセスの最大の利点は、マルチとは異なり、マルチコア CPU のリソースを最大限に活用できることです。 -Python では GIL の制限があり、CPU 割り当てのみを実行できるようにするため、基本的にマルチスレッドを使用でき、基本的にマルチプロセスを実行できます。使用済み。

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

マルチプロセス Process クラスとマルチスレッド Thread クラスには同様のメソッドがあります。詳細については、次のコードを参照してください。上記の例では、マルチプロセスとマルチスレッドの API インターフェースは同じです。同様に、作成されたプロセスが表示され、実行が開始され、プロセスの終了を待ちます。 Python でのマルチプロセス プログラミングを理解する

実行する必要のある関数には、プロセスのIDとpidが出力されており、親プロセスと子プロセスのID番号を確認することができます。linuでは主にプロセスがフォークされており、クエリを実行できます。プロセスの作成時に親プロセスと子プロセスの ID 番号を取得しますが、マルチスレッドではスレッド ID が見つかりません。実行結果は次のとおりです。オペレーティング システムでは、pstree を使用するのが最善です。クリア:

#!/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!'
実行中、join ステートメントがない場合、メイン プロセスはサブプロセスの終了を待たずに実行を継続することがわかります。次に、サブプロセスの実行を待ちます。 複数のプロセスを使用する場合、複数のプロセスの戻り値を取得するにはどうすればよいですか?そこで、次のようなコードを書きました。

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!

メインプロセスのサブプロセスの戻り値を取得するために、結果から値を返してみましたが、結果はありませんでした。プロセス内では、プロセス間に共有メモリがないため、プロセス間の対話は特別なデータ構造に依存する必要があり、プロセスを実行することはできません。プロセスの戻り値を取得しますが、上記のコードをスレッド化すると戻り値を取得できます。

3. プロセス間の対話 Queue

プロセス間で対話する場合、最初はマルチスレッドで同じ Queue 構造を使用できますが、マルチプロセスではマルチプロセスで Queue を使用する必要があります。以下のように:

├─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)

実際、これは上記の例を改良したもので、主にデータを保存するために Queue を使用していないため、プロセス間でデータを交換することができます。達成。

Queue を使用する場合、実際に実用的なのはソケットです。ソケット内で使用されるのは依然として送信と受信です。

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

4. プロセス間のやり取り Pipe

プロセス間でデータをやり取りする際にもPipeを使用することができます。 コードは次のとおりです:

#!/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

上記のコードでは、Pipeによって返される2つは主にSocketを使用します。データの送受信には親プロセスではparent_conn、子プロセスではchild_connを使用するため、子プロセスではsendメソッド、親プロセスでは受信メソッドrecvが使用されます。重要なのは、送受信の回数が明確にわかることですが、何か異常がある場合は、パイプが使用できない可能性があります。

5. プロセスプール pool

実際、マルチスレッドではプールを使用するのが一番便利だと感じます。

在使用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多进程编程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持PHP中文网。

更多Python でのマルチプロセス プログラミングを理解する相关文章请关注PHP中文网!

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