python-多进程


冯诺依曼体系

在这里插入图片描述

单进程

在Python中,执行一个Python脚本,就会创建一个进程。
可以用os.getpid()获得进程的PID

多进程

import os
import time
from multiprocessing import Process # 导入多进程的包

def cloudmusic(): # 模拟网易云音乐的进程
    for i in range(5):
        print(f"子进程{os.getpid()}正则播放 无人之岛...")
        time.sleep(1)

def lol(n): # 模拟lol进程(带参数的进程)
    for i in range(n):
        print(f"子进程{os.getpid()}游戏中,请勿打扰...")
        time.sleep(1)

def process_test():
    start_time = time.time()
    p1 = Process(target=cloudmusic) # 创建网易云音乐的进程
    # 带参数的进程使用args传参必须是元祖形式,参数顺序与方法形参顺序一致
    p2 = Process(target=lol,args=(8,)) # 创建lol的进程
    # 以kwargs传参
    #p2 = Process(target=lol,kwargs={"name":8}) 
    p1.daemon = True
    p2.daemon = False
    p1.start()  # 启动子进程p1
    p2.start()  # 启动子进程p2
    p1.join()
    p2.join()
    end_time = time.time()
    print(end_time - start_time)  # 这是主进程中最后1行代码,运行完,主进程结束

# 执行到创建子进程代码时,会自动拷贝其余代码来运行,在Linux和mac中,不会拷贝创建进程的代码
# 在Windows中,必须将创建子进程的代码放在main中,否则会递归无限制创建子进程,会报错
if __name__ == '__main__':
    process_test()

主进程和子进程

主进程:一般写的代码都是主进程。
子进程:在主进程通过Process类创建的进程对象就是子进程。

daemon进程守护

设置daemon = True,主进程执行完,不会等待该进程,同时所有daemon值为True的子线程将随主线程一起结束,而不论是否运行完成。
设置daemon = False(不设置时默认为False),主进程执行完,会等待该进程执行完再退出。

拿上面的例子来说,如果网易云音乐进程设置为True,那么输出会是这样的:
在这里插入图片描述

因为程序执行到输出时间后,主进程已经执行完,网易云音乐进程设置为True,那么主进程不会等网易云进程执行完毕,并随着主进程结束,将此进程一并结束,主进程完成的太快,所以看起来没有执行网易云音乐的子进程。相反,lol进程设置为False,主进程会等他执行完成,所以lol正常执行完毕。

join阻塞进程:

上面的例子中,p1.json(), 主进程会等p1执行完再执行剩下的代码。此时的输出为:
在这里插入图片描述时间是最后输出的,不同于前面的输出。
如果把上面例子中的p2.join()注释掉,那么输出的时间会是5秒多,因为主进程在5秒多p1执行完后就继续执行了,此时p2还没有执行完成,主进程没有p2执行完成就继续执行了。
在这里插入图片描述

daemon和join区别

总结一下,daemon和join看起来都是等待,区别是daemon是主进程先自己执行完再等待,join是执行到当前代码就等待,到子进程执行完毕再继续主进程。

进程不共享全局变量

from multiprocessing import Process

result = 0

def work01():
    global result
    result += 1
    print(f'work01中result值是{result}')

def work02():
    global result
    result += 1
    print(f'work02中result值是{result}')

def main():
    work01()
    work02()
    print(result)

def process_test():
    p1 = Process(target=work01)
    p2 = Process(target=work02)
    p1.start()
    p2.start()
    p1.join()
    p2.join()

if __name__ == '__main__':
    process_test()
    print(f'主进程中result的值是:{result}')

此例子中,最终输出的值为0,而不是我们设想的2。
因为每创建一个进程,CPU都会单独分配资源。所以,多个进程不会共享全局变量。
那么如何让多进程共享全局变量呢?此处就说到了队列。

共享进程数据

使用队列共享数据

from multiprocessing import Process, Queue

def work01(q):
    r = q.get() # 获取队列的值
    r += 1
    q.put(r) # 把值放入队列
    print(f'work01中q值是{r}')

def work02(q):
    r = q.get()
    r += 1
    q.put(r)
    print(f'work02中q值是{r}')

def process_test():
    q = Queue() # 创建队列
    q.put(0) # 把0放入队列
    p1 = Process(target=work01, args=(q,)) # 把队列传给子进程
    p2 = Process(target=work02, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print(f'主进程中q的值是:{q.get()}')

if __name__ == '__main__':
    process_test()

此时,我们就实现了输出为2。

使用Pipe共享数据

from multiprocessing import Process, Pipe

def f(conn):
    conn.send([42, None, 'hello'])  # send方法往管道放入值
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()  # 定义一个pipe,第一个参数接收父管道,第二个参数接收子管道
    p = Process(target=f, args=(child_conn,))  # 将子管道传给子进程
    p.start()
    print(parent_conn.recv())  # recv方法取出管道中的值
    p.join()

自定义进程类

自定义类继承进程类multiprocessing.Process。将进程方法写到run方法中,进程启动时自动调用。

import multiprocessing
import time

class MyProcess(multiprocessing.Process):
    def __init__(self):
        super(MyProcess, self).__init__()

    def run(self): # 进程启动的时候会调用此方法
        time.sleep(1)
        print(f'Hello!')

if __name__ == '__main__':
    p = MyProcess()
    p.start()
    p.join()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值