今日内容回顾

创建进程的多种方式

基于代码创建的进程
  1. 基于模块multiprocessing创建的进程
# 导入模块 multiprocessing import Process
from multiprocessing import Process
import time

def task():
    print('子进程运行开始')
    time.sleep(3print('子进程运行结束')
"""
创建进程的代码在不同的操作系统中,底层原理有区别。
在windows中,创建进程类似于导入模块,一定要在main内创建
列: if __name__ =='__main__':启动脚本如果没有,就会陷入死循环下去,直接报错!!!
在mac、linux中,创建进程类似于直接拷贝,不需要启动脚本,为了兼容性也可以使用。
"""
# windows一定要在启动脚本下面创建
if __name__=='__main__':
    # 创建一个进程对象
    p = Process(target=task,) 
    p.start()  # 告诉操作系统创建一个进程(异步操作)
    print('主进程')
  1. 使用类继承的方式创建的进程
# 创建一个类,继承父类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(3print('子进程运行结束')

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(3print('子进程运行结束')

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.锁只在处理数据的部分加来保证数据安全(只在争抢数据的环节加锁处理即可) 
"""

posted @   瓮小辉  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
点击右上角即可分享
微信分享提示