一、 创建进程的多种方法
首先回想上片我们讲到进程 进程就是运行中的代码 那我们怎么创建呢?
创建进程的两种方法:
1. 双击桌面图标程序(打开程序 底部代码运行就是创建进程)
2. 代码创建进程(两种方法) 需要用到模块mutiprocessing、Process
首先说明:
在创建进程的代码在不同的的操作系统中底层原理是不一样的有区别的!
在WiINDOWS里 创建进程类似于导入模块
需要用到 if __name__ == '__main__': 启动脚本 (要不然报错)
在MAC LINUX中 创建进程类似于直接拷贝
不需要启动脚本 但是为了更好的兼容性 加上启动脚本更好
方法1: 创建函数
from multiprocessing import Process
import time
def task(name):
print(f'{name}正在运行')
time.sleep(3)
print(f'{name}运行结束')
if __name__ == '__main__':
p = Process(target=task, args=('LebronJames',))
p.start()
print('主进程')
result: 主进程 LebronJames正在运行 LebronJames运行结束
方法2: 创建类
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print(f'{self.name}正在运行')
time.sleep(5)
print(f'{self.name}运行结束')
if __name__ == '__main__':
obj = MyProcess('LebronJames')
obj.start()
print('主进程')
result: 主进程 LebronJames正在运行 LebronJames运行结束
'''底层原理都是 先运行完父类的代码 创建一个进程空间运行子类的代码'''
二、 Join方法
'''join:主进程等待子进程运行结束之后再运行'''
from multiprocessing import Process
import time
def task(name, n):
print(f'{name}正在运行')
time.sleep(n)
print(f'{name}运行结束')
if __name__ == '__main__':
p1 = Process(target=task, args=('LebronJames', 1))
p2 = Process(target=task, args=('DwightHoward', 2))
p3 = Process(target=task, args=('Like', 3))
start_time = time.time()
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
end_time = time.time() - start_time
print('总耗时:%s' % end_time)
print('主进程')
result: LebronJames正在运行 DwightHoward正在运行 Like正在运行 LebronJames运行结束
DwightHoward运行结束 Like运行结束 总耗时:3.1185059547424316 主进程
三、 进程间数据默认隔离
多个进程数据彼此之间默认是相互隔离的(每个有各自的进程空间互不干扰)
如果真的想要交互 需要借助 管道与队列
from multiprocessing import Process
money = 100 # 父进程的全局money
def task():
global money
money = 666 # 子进程的局部money
print('子进程打印的money', money)
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join() # join等待子进程结束再运行父进程
print('父进程打印的money', money)
result: 子进程打印的money 666 父进程打印的money 100
'''总结到底还是 子是子 父是父 互不干扰'''
四、 进程间通行(IPC机制)
from multiprocessing import Queue
q = Queue(1) # 创建队列对象 括号内指定队列可以容纳的数据个数 默认:2147483647
q.put(111) # 2.往队列添加数据
print(q.full()) # 判断队列是否已经存满
q.put(222) # 超出数据存放极限 那么程序一致处于阻塞态 直到队列中有数据被取出
print(q.get_nowait()) # 3.从队列中取数据
print(q.get_nowait()) # 队列中如果没有数据可取 直接报错
print(q.get()) # 获取数据
print(q.empty()) # 判断队列是否已经空了
print(q.get()) # 超出数据获取极限 那么程序一致处于阻塞态 直到队列中有数据被添加
'''上述方法在多进程下不能准确的使用(或者失效)'''
IPC机制
1.主进程与子进程通信
2.子进程与子进程通信
from multiprocessing import Queue, Process
from multiprocessing import set_start_method
set_start_method('fork')
def procedure(q):
q.put('子进程procedure往队里中添加了数据')
def consumer(q):
print('子进程的consumer从队列中获取数据', q.get())
if __name__ == '__main__':
q = Queue()
p1 = Process(target=procedure, args=(q,))
p2 = Process(target=consumer, args=(q,))
p1.start()
p2.start()
print('主进程')
result: 主进程 子进程的consumer从队列中获取数据 子进程procedure往队里中添加了数据
五、 生产者消费者模型
生产者 产生数据
消费者 处理数据
例如爬虫 生产者:获取网页数据的代码(函数)爬
消费者:从网页数据中筛选出符合条件的数据(函数)筛选
完整的生产者消费者模型至少有三个部分
生产者 消息队列/数据库 消费者
六、 进程相关方法
查看进程号(每一个端口号进程号都是不一样的)
两种方法
from multiprocessing import current_process
current_process().pid # 获取进程号
import os
os.getpid() # 获取进程号
os.getppid() # 获取父的进程号
p1.terminate() # 销毁子进程
p1.is_alive() # 判断进程是否存活
from multiprocessing import Process
from multiprocessing import current_process
money = 100
def task():
global money
money = 666
print('子进程打印的money', money)
print('子进程的PID', current_process().pid)
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join()
print('父进程打印的money', money)
print('父进程的PID', current_process().pid)
七、 守护进程
什么是守护
伴随着守护对象的存活而存活 死亡而死亡
需要用到daemon方法
from multiprocessing import Process
import time
def task(name):
print('大内总管:%s存活' % name)
time.sleep(3)
print('大内总管:%s嗝屁' % name)
if __name__ == '__main__':
p = Process(target=task, args=('基佬',))
p.daemon = True
p.start()
print('天子LebronJames寿终正寝!!!')
result: 天子LebronJames寿终正寝!!!
八、 僵尸进程与孤儿进程
僵尸进程
进程已经运行结束 但是相关的资源并没有完全清空(子进程还在运行)
需要父进程参与回收
孤儿进程
父进程意外死亡 子进程正常运行 该子进程就称之为孤儿进程(单进程结束就结束了)
孤儿进程也不是没有人管 操作系统会自动分配福利院接收