Maison >développement back-end >Tutoriel Python >Comprendre la programmation multi-processus en python

Comprendre la programmation multi-processus en python

高洛峰
高洛峰original
2017-03-03 13:51:331274parcourir

L'éditeur suivant vous apportera une compréhension approfondie de la programmation multi-processus Python. L'éditeur le trouve plutôt bon, je vais donc le partager avec vous maintenant et le donner comme référence pour tout le monde. Suivons l'éditeur pour y jeter un œil

1. Contexte de la programmation multi-processus Python

Le plus grand avantage du multi-processus en Python est Pour en tirer pleinement parti, les ressources CPU multicœurs ne sont pas comme le multithreading en Python, qui est soumis aux restrictions GIL et ne peut être alloué qu'au CPU. Dans le multi-processus de Python, cela convient à toutes les occasions. le multi-threading peut être utilisé, donc fondamentalement, vous pouvez utiliser plusieurs processus.

Lors de la programmation multi-processus, cela est en fait similaire au multi-threading. Dans le package multi-threading, il existe une classe de thread Thread, dans laquelle il existe trois méthodes pour créer un thread et démarrer le. thread En fait, en multi-thread, dans la programmation de processus, il existe une classe de processus Process, qui peut également être utilisée en utilisant la méthode centralisée ; en multi-thread, les données en mémoire peuvent être partagées directement, comme des listes, etc. , mais dans les processus multi-processus, les données de la mémoire ne peuvent pas être partagées, il faut donc utiliser une structure de données distincte pour traiter les données partagées ; dans les processus multi-threads, le partage des données doit garantir l'exactitude des données, il faut donc faire quelque chose, mais dans. multi-processus, les verrous doivent rarement être pris en compte, car les informations de mémoire du processus ne sont pas partagées. Les données interactives entre les processus doivent passer par une structure de données spéciale, le contenu principal est le suivant :

Comprendre la programmation multi-processus en python

2. La classe multi-processus Process

La classe multi-processus Process et la classe multi-thread Thread ont des méthodes similaires. Les interfaces des deux sont fondamentalement les mêmes. Voir ci-dessous pour plus de détails Code :

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

Comme vous pouvez le voir dans l'exemple ci-dessus, les interfaces API multi-processus et multi-thread sont les mêmes. Le processus de création s'affiche, puis effectuez le démarrage pour commencer à s'exécuter, puis rejoignez et attendez la fin du processus.

Dans la fonction qui doit être exécutée, l'identifiant et le pid du processus sont imprimés, afin que vous puissiez voir les numéros d'identification du processus parent et du processus enfant. Sous Linux, les processus sont principalement dupliqués. Lors de la création d'un processus, les numéros d'identification du processus parent et du processus enfant peuvent être interrogés, mais l'ID du thread est introuvable en multi-threading. L'effet d'exécution est le suivant :

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!
<.>

dans Lors de l'interrogation de l'ID dans le système d'exploitation, il est préférable d'utiliser pstree, ce qui est clair :

├─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)
Lors de l'exécution, vous pouvez voir que s'il n'y a pas de jointure , le processus principal n'attendra pas la fin du processus enfant. Oui, il continuera à s'exécuter, puis attendra l'exécution du processus enfant.

Lors de l'utilisation de plusieurs processus, comment puis-je obtenir la valeur de retour de plusieurs processus ? Ensuite j'ai écrit le code suivant :

#!/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 = &#39;&#39;

  def run(self):
    self.res = self.func(*self.args)
    print self.name
    print self.res
    return (self.res,&#39;kel&#39;)

def func(name):
  print &#39;start process...&#39;
  return name.upper()

if __name__ == &#39;__main__&#39;:
  processes = []
  result = []
  for i in range(3):
    p = MyProcess(&#39;process&#39;,func,(&#39;kel&#39;,))
    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

Essayer de renvoyer une valeur à partir du résultat pour obtenir la valeur de retour du processus enfant dans le processus principal, Cependant, et il n'y a eu aucun résultat. Plus tard, j'ai pensé que dans le processus, les processus ne partagent pas de mémoire, il n'est donc évidemment pas possible d'utiliser des listes pour stocker des données. L'interaction entre les processus doit donc reposer sur des structures de données spéciales. ce qui précède Le code exécute uniquement le processus et ne peut pas obtenir la valeur de retour du processus. Cependant, si le code ci-dessus est modifié en thread, la valeur de retour peut être obtenue.

3. File d'attente d'interaction inter-processus

Lors de l'interaction entre les processus, vous pouvez d'abord utiliser la même structure de file d'attente en multi-threading. en multi-processus, vous devez utiliser la Queue en multiprocessing. Le code est le suivant :

#!/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 = &#39;&#39;

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

def func(name,q):
  print &#39;start process...&#39;
  q.put(name.upper())

if __name__ == &#39;__main__&#39;:
  processes = []
  q = multiprocessing.Queue()
  for i in range(3):
    p = MyProcess(&#39;process&#39;,func,(&#39;kel&#39;,q))
    processes.append(p)
  for i in processes:
    i.start()
  for i in processes:
    i.join()
  while q.qsize() > 0:
    print q.get()

En fait, c'est une amélioration de ce qui précède. Par exemple. Dans celui-ci, il n'y a pas Quel autre code doit être utilisé ? L'essentiel est d'utiliser Queue pour sauvegarder les données, afin que l'objectif d'échange de données entre les processus puisse être atteint.

Lors de l'utilisation de Queue, ce qui est réellement pratique, c'est le socket, car ce qui y est utilisé continue d'envoyer, puis de recevoir du recv.

Lors de l'interaction des données, le processus parent interagit en fait avec tous les processus enfants. Il n'y a fondamentalement aucune interaction entre tous les processus enfants, à moins que, mais il est également possible, par exemple, que chaque processus aille dans la file d'attente. pour récupérer des données, mais les verrous doivent être pris en compte à ce stade, sinon les données pourraient être confondues.

4. Interaction entre les processus Pipe

Pipe peut également être utilisé lors de l'échange de données entre processus. Le code est le suivant :

#!/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 = &#39;&#39;

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

def func(name,q):
  print &#39;start process...&#39;
  child_conn.send(name.upper())

if __name__ == &#39;__main__&#39;:
  processes = []
  parent_conn,child_conn = multiprocessing.Pipe()
  for i in range(3):
    p = MyProcess(&#39;process&#39;,func,(&#39;kel&#39;,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()

Dans le code ci-dessus, les deux sockets renvoyées dans Pipe sont principalement utilisées pour transmettre et recevoir des données. Dans le processus parent, parent_conn est utilisé, et dans le processus enfant, c'est child_conn, Ainsi, le processus enfant envoie des données en utilisant la méthode d'envoi et la méthode de réception recv

dans le processus parent ne peut plus être utilisée.

5. Pool de processus pool

En fait, lorsque vous utilisez plusieurs processus, je pense que l'utilisation de pool est la plus pratique en multi-. threading, c'est Il n'y a pas de pool.

在使用pool的时候,可以限制每次的进程数,也就是剩余的进程是在排队,而只有在设定的数量的进程在运行,在默认的情况下,进程是cpu的个数,也就是根据multiprocessing.cpu_count()得出的结果。

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

#!/usr/bin/env python

import multiprocessing

def func(name):
  print &#39;start process&#39;
  return name.upper()

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

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

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

#!/usr/bin/env python

import multiprocessing
import time
def func(name):
  print &#39;start process&#39;
  time.sleep(2)
  return name.upper()

if __name__ == &#39;__main__&#39;:
  results = []
  p = multiprocessing.Pool(5)
  for i in range(7):
    res = p.apply_async(func,args=(&#39;kel&#39;,))
    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中文网。

更多Comprendre la programmation multi-processus en python相关文章请关注PHP中文网!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn