Python多进程实现原理

多进程

关键字

#p1.terminate() #主动杀死子进程
#p1.is_alive()  #判断子进程是否存活

开启进程的俩种方式

#方式1:直接使用默认的Process类
#实验目的:查看进程起的时候是需要时间的,起的时间足够python把下面的代码运行完,
from multiprocessing import Process
import time

def task(name):
    print('1、%s is running' %name)
    time.sleep(5)
    print('2、%s is done' %name)
if __name__=='__main__':
    p=Process(target=task,args=('alex',)) #args后面使用的是一个元组的形式
    p.start()  #起进程是需要时间的,起的时间足够python把下面的代码运行完
    # time.sleep(1) #在start()后面sleep(1)秒,会发现先执行第一个print.
    print('3、主')

#方法2:自定义一个Process类
from multiprocessing import Process
import time
class MyProcess(Process):
    def __init__(self,name):
        super(MyProcess,self).__init__()
        self.name=name #自定义的功能
    def run(self):  #自定义的Process类,必须要自定义一个run方法。
        print('1、%s is running' %self.name)
        time.sleep(3)
        print('2、%s is done' %self.name)
if __name__=='__main__':
    p=MyProcess('进程1')
     p.start()  #相等于p.run(),执行自定义进程的方法
#     time.sleep(1)

进程之间的内存空间是隔离的

#实验目的:使用pid验证进程和进程之间数据是相互隔离的
from multiprocessing import Process
import time,os
n=100
def task():
    global n   #修改全局变量
    time.sleep(1)
    n=0
    print(n,os.getpid(),os.getppid())

if __name__=='__main__':
    p=Process(target=task,)
    p.start()
    print(p.is_alive())
    p.join()  #等待p这个进程运行完成才运行下面的代码
    print(p.is_alive())  #判断p这个进程是否存活
    print(n,os.getpid(),os.getppid())
# True
# 0 7480 2156  #n的值,子进程的pid,和子进程的父进程的pid
# False
# 100 2156 8312 #n的值,主进程的pid,父进程的pid(pycham的pid)

进程中的join方法使用

#实验目的,使用join方法实现并发执行,并且查看到起进程是需要耗时间的,并且很长
from  multiprocessing import Process
import os,time

def task(n):
    print('1、%s is running' %n,os.getpid(),os.getppid())
    time.sleep(n)
    print('2、%s is done' %n,os.getpid(),os.getppid())

if __name__=='__main__':
    p1=Process(target=task,args=(1,))
    p2=Process(target=task,args=(2,))
    p3=Process(target=task,args=(3,))
    stat=time.time()
    p_l=[p1,p2,p3]
    for p in p_l:
        p.start()
    for p in p_l:
        p.join()
    stop=time.time()
    print('主进程,%s'%str(stop-stat),os.getpid(),os.getppid())
# 1、1 is running 4680 6188
# 1、2 is running 9988 6188
# 1、3 is running 8564 6188
# 2、1 is done 4680 6188
# 2、2 is done 9988 6188
# 2、3 is done 8564 6188
# 主进程,3.3031890392303467 6188 8312  #3.3秒,由此可以看到起一个进程是需要耗时的,6188是主进程的pid,8312是pycharm的pid

进程对象的其它属性和方法

#主动杀死进程,杀死进程也是给系统发起一个信号,需要比较长的时间才能把进程杀死
from  multiprocessing import Process
import time
import os
def task(n):
    print('1、%s is running' %n,os.getpid(),os.getppid())
    time.sleep(3)
    print('2、%s is done' %n,os.getpid(),os.getppid())

if __name__=='__main__':
    stat=time.time()
    p1=Process(target=task,args=('lqx',))
    p1.start()
    time.sleep(1)
    print(p1.is_alive())
    p1.terminate()  #给系统发一个信号,杀死子进程,这个是需要时间的,所有下面的判断,子进程还是存活的,如果休息一秒,会发现子进程已经没了
    time.sleep(1)
    print(p1.is_alive())
    p1.join()
    stop=time.time()
    print('3、主进程',stop-stat,os.getpid(),os.getppid())

守护进程的使用

主进程的代码运行完毕以后守护进程就没有意义存在了,会立马死掉
#守护进程:当子进程执行的任务在父进程代码运行完毕后就没有必要存在的必要了,那么该子进程需要设置为守护进程。
#实验目的:开启守护进程,是不能在守护进程中再次开启子进程的。
from multiprocessing import Process
import time,os
def bar():
    print('bar')
def task(name):
    # p=Process(target=bar,)  #开启守护进程后不允许再次开启子进程
    # p.start()
    print('%s is runing' %name)
    time.sleep(2)
    print('%s is end' %name)
if __name__=='__main__':
    p=Process(target=task,args=('lqx',))
    p.daemon=True  #守护进程开启必须在开启进程之前
    p.start()
    time.sleep(1)
    print('主进程')
# lqx is runing  #在休息的1秒中的时候,守护进程启动,然后瞬间运行了第一条,然后sleep了,主进程运行完成了,程序结束
# 主进程

#主进程代码运行完毕,守护进程就会结束
from multiprocessing import Process
from threading import Thread
import time
def foo():
    print(123)
    time.sleep(1)
    print('end')
def bar():
    print(456)
    time.sleep(2)
    print('end456')

if __name__=='__main__':
    p=Process(target=foo)
    p2=Process(target=bar)

    p.daemon=True

    p.start()
    p2.start()
    # time.sleep(0.5)
    print('main____')
# main____
# 456
# end456

#没有打印123的原因是没有等到p1这个进程启动,代码就已经运行完成了,导致123没有出来,如果电脑运行过快,申请内存空间快,在P2.start()的时候,p1已经启动了,有可能就打印出来123,只要main__出现,123就不会出现了,p1(守护进程)立马会死掉
# 但是打印456,原因是:主进程需要等待非守护进程死掉后把pid给回收掉

进程的互斥锁

#实验目的:在修改数据文件的时候,如果并发执行,会导致数据文件修改紊乱的问题,因此使用互斥锁把并发改为串行,一个进程一个进程的去修改数据文件,保证数据的安全性
from multiprocessing import Process,Lock
import time,os,json,random
def search():
    time.sleep(random.randint(1,2))
    dic=json.load(open('db.txt','r',encoding='utf-8'))
    print('%s 查看余票为%s' %(os.getpid(),dic['count']))
def get():
    dic=json.load(open('db.txt','r',encoding='utf-8'))
    if dic['count'] >0:
        dic['count']-=1
        time.sleep(random.randint(0,1))
        json.dump(dic,open('db.txt','w',encoding='utf-8'))
        print('%s 购票成功!' %os.getpid())
def task(mutex):
    search()
    mutex.acquire()
    get()
    mutex.release()
if __name__=='__main__':
    mutex=Lock()  #添加一个互斥锁,生成一个实例
    for i in range(10):
        p=Process(target=task,args=(mutex,))
        p.start()

进程实现队列

from multiprocessing import Queue

q=Queue(3)  #设置队列最大长度
q.put('first') #添加一个值到队列中
q.put(2)
q.put({'count':3})
# q.put('fourth')   #如果添加值的个数超出队列长度,会发生队列阻塞。
# q.put('fourth',block=False)   #q.put_nowait('fourth')   #发生阻塞的时候主动抛出一个异常queue.Full
# q.put('fourth',block=True,timeout=3)   #发生阻塞的时候等待3秒主动抛出一个异常queue.Full

print(q.get())  #从队列中取出一个值
print(q.get())
print(q.get())
# print(q.get())  #如果队列为空,会发生队列阻塞
# print(q.get(block=False))   #如果队列为空,会主动抛出一个异常 queue.Empty
print(q.get(block=True,timeout=3))   #发生阻塞的时候等待3秒主动抛出一个异常queue.Empty

生产者和消费者模型

#实验目的:实现生产者生产东西,消费者去消费,生产多少消费多少
#生产者->队列->消费者
#生产者生产完成后,消费者去消费,会出现一种情况生产者p生产完成后就子进程就结束了,但是可能有多个,消费c在取值取到空的时候,会一直处于死循环中,一直卡在c.get()这一步
#解决方法一:
#在生产者生产完成后主进程q.put(None),有几个消费者就应该put几个空,然后当消费者取到空的时候,break掉循环
from multiprocessing import Process,JoinableQueue
import time,random
def producer(name,food,q):
    for i in range(3):
        res='%s%s' %(food,i)
        time.sleep(random.randint(1,2))
        q.put(res)
        print('厨师%s生产%s'%(name,res))

def consumer(name,q):
    while True:
        res=q.get()
        if res is None:break
        time.sleep(random.randint(1,2))
        print('吃货%s吃掉了%s'%(name,res))

if __name__=='__main__':
    q=JoinableQueue()

    q1=Process(target=producer,args=('lqx','水',q))
    q2=Process(target=producer,args=('yft','食物',q))

    c1=Process(target=consumer,args=('dog',q))
    c2=Process(target=consumer,args=('horse',q))
    c3=Process(target=consumer,args=('pig',q))

    q_l=[q1,q2,c1,c2,c3]
    for qn in q_l:qn.start()
    q1.join()
    q2.join()

    q.put(None)
    q.put(None)
    q.put(None)
    print('主')

#解决方法2:守护进程在生产者消费者模型中的应用
from multiprocessing import Process,JoinableQueue
import time
import random

def producer(name,food,q):
    for i in range(3):
        res='%s %s' %(name,food)
        time.sleep(random.randint(1,2))
        q.put(res)
        print('%s 生产出来 %s' %(name,food))
def consumer(name,q):
    while True:
        res=q.get()
        if res is None:break
        time.sleep(random.randint(1,2))
        print('%s 吃掉 %s' %(name,res))
        q.task_done()  #消费者每取走一个值,给q.join()发送确认
if __name__=='__main__':
    q=JoinableQueue()

    p1=Process(target=producer,args=('lqx','骨头',q))
    p2=Process(target=producer,args=('yft','肉',q))

    c1=Process(target=consumer,args=('dog',q))
    c2=Process(target=consumer,args=('pig',q))
    c3=Process(target=consumer,args=('horse',q))

    p1.start()
    p2.start()

    c1.daemon=True
    c2.daemon=True
    c3.daemon=True  #不添加消费者为守护进程,程序运行完成后,消费者c还是会循环取值,取到空值,卡在原地,把消费者设置为守护进程,等
    c1.start()
    c2.start()
    c3.start()

    p1.join()
    p2.join() #保障生产者把数据生产完
    q.join()  #主进程可以暂停,等待队列结束
    print('主')

进程和线程之间的区别

  • 线程间资源共享,进程间资源独立

猜你喜欢

转载自blog.csdn.net/qq_29462849/article/details/82992717