> 백엔드 개발 > 파이썬 튜토리얼 > Python의 다중 프로세스 프로그래밍 이해

Python의 다중 프로세스 프로그래밍 이해

高洛峰
풀어 주다: 2017-03-03 13:51:33
원래의
1279명이 탐색했습니다.

다음 편집기는 Python 다중 프로세스 프로그래밍에 대한 심층적인 이해를 제공합니다. 에디터가 꽤 좋다고 생각해서 지금 공유해서 참고용으로 올려보겠습니다. 편집기를 따라 살펴보겠습니다

1. Python 다중 프로세스 프로그래밍 배경

Python에서 다중 프로세스의 가장 큰 이점은 멀티 코어 CPU 리소스는 Python의 멀티 스레딩과 달리 GIL 제한이 적용되며 Python의 멀티 프로세스에서는 기본적으로 모든 경우에 적합합니다. 멀티스레딩을 사용할 수 있으므로 기본적으로 여러 프로세스를 사용할 수 있습니다.

멀티 프로세스 프로그래밍을 할 때 실제로는 멀티 스레딩과 유사합니다. 멀티 스레딩 패키지 스레딩에는 스레드 클래스 Thread가 있는데, 여기에는 스레드를 생성하고 시작하는 세 가지 방법이 있습니다. 실제로 멀티스레딩에는 프로세스 클래스인 Process가 있는데, 이는 멀티스레드에서 중앙 집중식 방법을 사용하여 목록과 같은 메모리의 데이터를 직접 공유할 수도 있습니다. 그러나 다중 프로세스에서는 메모리 데이터를 공유할 수 없으므로 다중 스레드에서 공유 데이터를 처리하려면 별도의 데이터 구조를 사용해야 하며 데이터 공유는 데이터의 정확성을 보장해야 하므로 조치를 취해야 합니다. , 그러나 다중 프로세스에서는 프로세스 메모리 정보가 공유되지 않기 때문에 잠금을 거의 고려하지 않아야 합니다. 다중 프로세스에서 주요 내용은 다음과 같습니다. 🎜>

Python의 다중 프로세스 프로그래밍 이해

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를 찾을 수 없습니다. 실행 효과는 다음과 같습니다.

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!
로그인 후 복사

운영 체제에서 ID를 쿼리할 때는 pstree를 사용하는 것이 가장 좋으며, 다음을 삭제합니다.

├─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프로세스 간 상호작용 시 먼저 멀티스레딩에서 동일한 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를 사용하여 데이터를 저장하므로 프로세스 간 데이터 교환 목적을 달성할 수 있습니다.

Queue를 사용할 때 실제로 실용적인 것은 소켓입니다. 그 안에 사용되는 것은 여전히 ​​​​보내고 수신하는 것입니다.

데이터 상호 작용을 수행할 때 상위 프로세스는 실제로 모든 하위 프로세스와 상호 작용합니다. 데이터를 가져오지만 이때 잠금을 고려해야 합니다. 그렇지 않으면 데이터가 혼동될 수 있습니다.

4. 프로세스 간 상호작용 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)

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()
로그인 후 복사

위 코드에서는 Pipe에서 반환된 두 개의 소켓이 주로 데이터 송수신에 사용되며, 상위 프로세스에서는 parent_conn이 사용되고 하위 프로세스에서는 child_conn이 사용됩니다. 자식 프로세스는 send 메소드를 사용하여 데이터를 보내고, 부모 프로세스에서는 수신 메소드인 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多进程编程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持PHP中文网。

更多Python의 다중 프로세스 프로그래밍 이해相关文章请关注PHP中文网!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿