今日内容回顾
创建进程的多种方式
基于代码创建的进程
- 基于模块multiprocessing创建的进程
# 导入模块 multiprocessing import Process
from multiprocessing import Process
import time
def task():
print('子进程运行开始')
time.sleep(3)
print('子进程运行结束')
"""
创建进程的代码在不同的操作系统中,底层原理有区别。
在windows中,创建进程类似于导入模块,一定要在main内创建
列: if __name__ =='__main__':启动脚本如果没有,就会陷入死循环下去,直接报错!!!
在mac、linux中,创建进程类似于直接拷贝,不需要启动脚本,为了兼容性也可以使用。
"""
# windows一定要在启动脚本下面创建
if __name__=='__main__':
# 创建一个进程对象
p = Process(target=task,)
p.start() # 告诉操作系统创建一个进程(异步操作)
print('主进程')
- 使用类继承的方式创建的进程
# 创建一个类,继承父类Process
class MyProcess(Process):
# 重写父类中init的方法
def __init__(self, name):
super().__init__()
self.name = name
# 重写父类中run方法
def run(self):
print(f'{self.name}正在运行')
time.sleep(5)
print(f'{self.name}运行结束')
if __name__ == '__main__':
# 创建一个对象
obj = MyProcess('jason')
# 告诉操作系统创建一个进程
obj.start()
print('主进程')
join方法
# join:使用join方法后,表示主进程需等待子进程运行结束之后才会运行。
def task():
print('子进程运行开始')
time.sleep(3)
print('子进程运行结束')
if __name__=='__main__':
# 创建一个进程对象
p = Process(target=task,)
p.start() # 告诉操作系统创建一个进程(异步操作)
p.join()# 等待子进程运行结束后主进程才会执行
print('主进程')
进程间数据默认隔离
多个进程数据彼此之间默认是相互隔离的
如果真的想交互,需要借助于管道或队列
进程间通信(ipc机制)
队列:先进先出
代码实操:
# 导入multiprocessing中的Queue类
from multiprocessing import Queue
# 创建队列对象
q = Queue(3) # 括号内填入整数,指定队列可以容纳的数据个数,默认数值为:2147483647
# 1.往队列里添加数据.put()
# 对象句点符的方式点出put方法,括号内填入需要添加的数据
p.put(111) # 添加数据
p.put(222)
p.put(333) # 如果添加的数据超过数据存放极限,那么程序会一直处于阻塞态,直到队列中有数据被取出。
p.full() # 判断队列是否已存满。
# 2.从队列中取出数据.get()
p.get() # 取出数据,遵循7先进先出原则依次取出
p.get()
p.get() # 如果取出数据超出队列当前数据量,那么程序会一直处于阻塞态,直到队列中有数据添加进来。
p.empty # 判断队列是否已经空了
# 3.从队列获取数据的第二中方法 .get_nowait()
q.get_nowait() # 这种方法比较暴躁,如果获取数据超出限制它会直接报错!!!
"""
q.full()
q.empty()
q.get_nowait()
上述方法在多进程下不能准确使用(失效)!!!
"""
IPC机制
主进程与子进程通信,子进程与子进程通信。
代码实操:
# 使用队列方式建立第三方通道,实现进程之间通信
from multiprocessing import Queue, Process
def procedure(q):
q.put('子进程procedure往队里中添加了数据')
def consumer(q):
print('子进程的consumer从队列中获取数据', q.get())
if __name__ == '__main__':
q = Queue() # 在主进程中产生q对象 确保所有的子进程使用的是相同的q
p1 = Process(target=procedure, args=(q,))
p2 = Process(target=consumer, args=(q,))
p1.start()
p2.start()
print('主进程')
生产者消费者模型
生产者:生产、制造数据
消费者:处理数据
比如我们之前学习的爬取网页操作
生产者相当于我们获取网页数据的代码
消费者相当于从网页数据中筛选出符条件的数据代码
完整的生产者消费者模型至少要有三个部分
生产者>>>>消息队列/数据库>>>消费者
进程相关方法
查看进程号
当每个程序在运行的时候系统都会给其分配一个进程号。用来区分每个运行程序的不同。
from multiprocessing import current_process
import os
current_process().pid # current_process().pid 查看当前进程的进程号,
os.getpid() # 查看当前进程的进程号
os.getppid() # 查看当前进程的父进程号
销毁子进程、判断进程是否存活
from multiprocessing import Process
import time
def task():
print('子进程运行开始')
time.sleep(3)
print('子进程运行结束')
if __name__=='__main__':
p = Process(target=task,)
p.start() # 告诉操作系统创建一个进程
p.terminate() # 销毁子进程,
time.sleep(0.1)
p.is_alive() # 判断进程是否存活
print('主进程')
守护进程
守护进程指伴随着守护对象的存活而存活,死亡而死亡。
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()
p.daemon = True # 必须在start之前执行
print('天子Jason寿终正寝!!!')
僵尸进程与孤儿进程
僵尸进程
进程已经运行结束,但是相关的资源并没有被完全清空
需要父进程进行回收
孤儿进程
父进程意外死亡子进程正常运行,该子进程无人回收相关资源子进程就被称之为孤儿进程
孤儿进程也不是没人管,操作系统监测到这种孤儿进程存在,会自动分配类似于福利院一样的机制将其接收
互斥锁
多个进程操作同一份数据的时候,可能会出现错乱的问题
针对这种问题解决方式就是加锁处理,将并发变成串行,牺牲效率但是保证了数据安全。
from multiprocessing import Process, Lock
import json
import time
import random
# 查票
def search(i):
# 文件操作读取票数
with open('data','r',encoding='utf8') as f:
dic = json.load(f)
print('用户%s查询余票:%s'%(i, dic.get('ticket_num')))
# 字典取值不要用[]的形式 推荐使用get 你写的代码打死都不能报错!!!
# 买票 1.先查 2.再买
def buy(i):
# 先查票
with open('data','r',encoding='utf8') as f:
dic = json.load(f)
# 模拟网络延迟
time.sleep(random.randint(1,3))
# 判断当前是否有票
if dic.get('ticket_num') > 0:
# 修改数据库 买票
dic['ticket_num'] -= 1
# 写入数据库
with open('data','w',encoding='utf8') as f:
json.dump(dic,f)
print('用户%s买票成功'%i)
else:
print('用户%s买票失败'%i)
# 整合上面两个函数
def run(i, mutex):
search(i)
# 给买票环节加锁处理,让第一个抢到钥匙的人才能购买到票
mutex.acquire()
buy(i)
# 释放锁
mutex.release()
if __name__ == '__main__':
# 在主进程中生成一把锁 让所有的子进程抢 谁先抢到谁先买票
mutex = Lock()
for i in range(1,11):
p = Process(target=run, args=(i, mutex))
p.start()
"""
扩展 行锁 表锁
注意:
1.锁不要轻易的使用,容易造成死锁现象(我们写代码一般不会用到,都是内部封装好的)
2.锁只在处理数据的部分加来保证数据安全(只在争抢数据的环节加锁处理即可)
"""
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用