Maison > développement back-end > Tutoriel Python > Introduction détaillée au multi-processus Python (avec exemples)

Introduction détaillée au multi-processus Python (avec exemples)

不言
Libérer: 2018-09-20 17:23:43
original
4191 Les gens l'ont consulté

Le contenu de cet article porte sur qu'est-ce que SAPI en PHP ? Comment y parvenir ? (Images et texte), il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.

Process

Python est un langage qui s'exécute dans l'interpréteur. En recherchant des informations, nous savons qu'il existe un verrou global (GIL) en python, qui ne peut pas être utilisé lors de l'utilisation de plusieurs processus (. Thread). Avantages du multicœur. En utilisant Multiprocess, vous pouvez tirer parti du multicœur pour réellement améliorer l’efficacité.
Si le processus multithread est gourmand en CPU, alors le multithread n'améliorera pas beaucoup l'efficacité. Au contraire, cela peut entraîner une diminution de l'efficacité en raison du changement fréquent de threads. s'il est gourmand en E/S, les processus multithread peuvent utiliser le temps d'inactivité en attendant le blocage des E/S pour exécuter d'autres threads afin d'améliorer l'efficacité.

Créer un processus

Méthodes spéciales pour les systèmes Linux et Mac

1. Le principe de création d'un processus enfant sous Linux :
1). , si le processus parent se termine, le processus enfant se termine également ;
2). Il y a d'abord le processus parent, puis le processus enfant, qui est implémenté via la fonction fork ;

2. valeur de la fonction fork : appelle cette méthode une fois et renvoie deux fois ;

  • Le processus enfant généré renvoie un 0

  • Le processus parent renvoie le pid du processus enfant ;

3. Window peut-il également utiliser la fonction fork ?

Windows没有fork函数, Mac有fork函数(Unix -> Linux, Unix-> Mac),
封装了一个模块multiprocessing
Copier après la connexion

4. Méthodes courantes :

  • os.fork()

  • os.getpid() : Obtenez le pid du processus en cours ;

  • os .getppid() : identifiant du processus parent, obtient le numéro d'identification du processus parent du processus actuel

import  os
import  time
print("当前进程(pid=%d)正在运行..." %(os.getpid()))
print("当前进程的父进程(pid=%d)正在运行..." %(os.getppid()))
print("正在创建子进程......")
pid = os.fork()
pid2 = os.fork()
print("第1个:", pid)
print("第2个: ", pid2)

if pid == 0:
    print("这是创建的子进程, 子进程的id为%s, 父进程的id为%s"
          %(os.getpid(), os.getppid()))
else:
    print("当前是父进程[%s]的返回值%s" %(os.getpid(), pid))
time.sleep(100)
Copier après la connexion

win system

Sous win system, quand en créant un processus à l'aide du multiprocessing.Process instancié, vous devez ajouter 'if __name__=="__main__"', sinon ce sera le cas. L'erreur suivante se produit :

RuntimeError:

An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.

This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:

   if __name__ == '__main__':
       freeze_support()
       ...

The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
Copier après la connexion
import  multiprocessing
def job():
    print("当前子进程的名称为%s" %(multiprocessing.current_process()))
if __name__=="__main__":    #win操作系统需要加上,否则会出现异常报错RuntimeError

    # 创建一个进程对象(group=None, target=None, name=None, args=(), kwargs={})
    p1 = multiprocessing.Process(target=job)
    p2 = multiprocessing.Process(target=job)
    # 运行多进程, 执行任务
    p1.start()
    p2.start()

    # 等待所有的子进程执行结束, 再执行主进程的内容
    p1.join()
    p2.join()
    print("任务执行结束.......")
Copier après la connexion

Introduction détaillée au multi-processus Python (avec exemples)

Créez plusieurs processus en remplaçant la classe multiprocessing.Process

from multiprocessing import Process
import multiprocessing
class JobProcess(Process):
    # 重写Process的构造方法, 获取新的属性
    def __init__(self,queue):
        super(JobProcess, self).__init__()
        self.queue = queue
    # 重写run方法, 将执行的任务放在里面即可
    def run(self):
        print("当前进程信息%s" %(multiprocessing.current_process()))

if __name__=="__main__":
    processes = []
    # 启动10个子进程, 来处理需要执行的任务;
    for i in range(10):
        #示例化类,创建进程
        p = JobProcess(queue=3)
        processes.append(p)
        #启动多进程,执行任务
        p.start()
    #等待所有的子进程结束,再执行主进程
    [pro.join() for pro in processes]
    print("任务执行结束")
Copier après la connexion

Introduction détaillée au multi-processus Python (avec exemples)

Démon processus

Fil démon :

setDeamon:
    True: 主线程执行结束, 子线程不再继续执行;
    Flase:
Copier après la connexion

Processus démon :

  setDeamon:
    True: 主进程执行结束, 子进程不再继续执行;
    Flase:
Copier après la connexion
import multiprocessing
import time
def deamon():
    #守护进程:当主程序运行结束,子进程也结束
    name = multiprocessing.current_process()
    print("%s开始执行" %(name))
    time.sleep(3)
    print("执行结束")

if __name__=="__main__":
    p1 = multiprocessing.Process(target=deamon,name='hello')
    p1.daemon = True
    p1.start()
    time.sleep(2)
    print("整个程序执行结束")
Copier après la connexion

Introduction détaillée au multi-processus Python (avec exemples)

Terminer le processus

Certains processus peuvent effectuer des tâches en boucle sans fin, à ce moment nous terminons manuellement le processus
terminate ()

import multiprocessing
import time

def job():
    name = multiprocessing.current_process()
    print("%s进程开启" %(name))
    time.sleep(3)
    print("进程结束")

if __name__=="__main__":
    p = multiprocessing.Process(target=job)
    print("进程开启:",p.is_alive())
    p.start()
    print("进程开启:",p.is_alive())
    p.terminate()
    print("进程开启:",p.is_alive())
    time.sleep(0.001)
    print("进程开启:",p.is_alive())
    print("程序执行结束")
Copier après la connexion

Introduction détaillée au multi-processus Python (avec exemples)

Des tâches gourmandes en calcul et en E/S

Les tâches gourmandes en calcul se caractérisent par une grande quantité de calculs consommant des ressources CPU, tels que le calcul de pi, le décodage haute définition de vidéos, etc., le tout reposant sur la puissance de calcul du CPU. Bien que ce type de tâche gourmande en calcul puisse également être réalisé en multitâche, plus il y a de tâches, plus le temps consacré au changement de tâche est long et plus l'efficacité du processeur dans l'exécution des tâches est faible. utilisation du CPU, gourmande en calcul. Le nombre de tâches simultanées doit être égal au nombre de cœurs du CPU. Les tâches gourmandes en ressources informatiques consomment principalement des ressources CPU, l'efficacité de l'exécution du code est donc cruciale. Les langages de script comme Python fonctionnent de manière très inefficace et sont totalement inadaptés aux tâches gourmandes en calcul. Pour les tâches gourmandes en calcul, il est préférable d’écrire en langage C.

Le deuxième type de tâche est gourmand en E/S. Les tâches impliquant des E/S réseau et disque sont toutes des tâches gourmandes en E/S. La caractéristique de ce type de tâche est que la consommation CPU est très faible, et la plupart du temps. de la tâche est d'attendre la fin de l'opération IO (car la vitesse des IO est beaucoup plus lente que la vitesse du processeur et de la mémoire). Pour les tâches gourmandes en E/S, plus il y a de tâches, plus l'efficacité du processeur est élevée, mais il y a une limite. Les tâches les plus courantes sont les tâches gourmandes en E/S, telles que les applications Web.

Comparaison entre multi-processus et multi-thread

Le plus grand avantage du mode multi-processus est sa grande stabilité, car si un sous-processus plante, cela n'affectera pas le processus principal et d'autres sous-processus. (Bien sûr, si le processus maître raccroche, tous les processus raccrocheront, mais le processus maître n'est responsable que de l'allocation des tâches, et la probabilité de raccrocher est faible) Le célèbre Apache a d'abord adopté le mode multi-processus.

L'inconvénient du mode multi-processus est que le coût de création d'un processus est élevé Sous les systèmes Unix/Linux, appeler fork est acceptable, mais créer des processus sous Windows coûte cher. De plus, le nombre de processus que le système d'exploitation peut exécuter simultanément est également limité, tant en mémoire qu'en mémoire. Sous la limitation du processeur, si des milliers de processus s'exécutent en même temps, le système d'exploitation aura même des problèmes de planification.

多线程模式通常比多进程快一点, 但是也快不到哪去, 而且, 多线程模式致命的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃, 因为所有线程共享进程的内存。 在Windows上, 如果一个线程执行的代码出了问题, 你经常可以看到这样的提示:“该程序执行了非法操作, 即将关闭”, 其实往往是某个线程出了问题, 但是操作系统会强制结束整个进程。
这里通过一个计算密集型任务,来测试多进程和多线程的执行效率。

import multiprocessing
import threading
from mytimeit import timeit

class JobProcess(multiprocessing.Process):
    def __init__(self,li):
        super(JobProcess, self).__init__()
        self.li = li
    def run(self):
        for i in self.li:
            sum(i)


class JobThread(threading.Thread):
    def __init__(self,li):
        super(JobThread, self).__init__()
        self.li = li
    def run(self):
        for i in self.li:
            sum(i)
@timeit
def many_processs():
    li = [[24892,23892348,239293,233],[2382394,49230,2321234],[48294,28420,29489]]*10
    processes = []
    for i in li :
        p = JobProcess(li)
        processes.append(p)
        p.start()
    [pro.join() for pro in processes]
    print("多进程执行任务结束,✌")
@timeit
def many_thread():
    #创建进程和销毁进程是时间的,如果li长度不够,会造成多线程快过多进程
    li = [[24892,23892348,239293,233],[2382394,49230,2321234],[48294,28420,29489]]*1000
    threads = []
    for i in li :
        t = JobThread(li)
        threads.append(t)
        t.start()
    [thread.join() for thread in threads]
    print("多线程执行任务结束,✌")
if __name__ =="__main__":
    many_processs()
    many_thread()
Copier après la connexion

Introduction détaillée au multi-processus Python (avec exemples)

进程间通信-生产者消费者模型与队列

演示了生产者和消费者的场景。生产者生产货物,然后把货物放到一个队列之类的数据结构中,生产货物所要花费的时间无法预先确定。消费者消耗生产者生产的货物的时间也是不确定的。
通过队列来实现进程间的通信

import multiprocessing
import threading
from multiprocessing import Queue

class Producer(multiprocessing.Process):
    def __init__(self,queue):
        super(Producer, self).__init__()
        self.queue = queue
    def run(self):
        for i in range(13):
            #往队列添加内容
            self.queue.put(i)
            print("生产者传递的消息为%s" %(i))
        return self.queue

class Consumer(multiprocessing.Process):
    def __init__(self,queue):
        super(Consumer, self).__init__()
        self.queue = queue
    def run(self):
        #获取队列内容
        #get会自动判断队列是否为空,如果是空, 跳出循环, 不会再去从队列获取数据;
        while True:
            print("进程获取消息为:%s" %(self.queue.get()))
if __name__=="__main__":
    queue  = Queue(maxsize=100)
    p = Producer(queue)
    p.start()
    c = Consumer(queue)
    c.start()
    p.join()
    c.join(2)
    c.terminate()   #终止进程
    print("进程间通信结束,( •̀ ω •́ )y")
Copier après la connexion

Introduction détaillée au multi-processus Python (avec exemples)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal