并发编程 2 进程
同步与异步
# 用来表达任务的提交方式 同步 : 提交完任务之后原地等待任务的返回结果,期间不做任何事 异步 : 提交完任务之后不愿地等待任务的返回结果,直接去做其他事,有结果自动通知.
异步非阻塞 (效率最高
创建进程的多种方式
# 1.鼠标双击软件图标 # 2.python代码创建进程 """ 在不同的操作系统中创建进程底层原理不一样 windows : 以导入模块的形式创建进程 linux/mac :以拷贝代码的形式创建进程 """ from multiprocessing import Process import time def task(name): print('task is running',name) time.sleep(3) print('task is over',name) if __name__ == '__main__': # p1 = Process(target=task, args=('jason',)) # 位置参数 p1 = Process(target=task, kwargs={'name':'jason123'}) # 关键字参数 p1.start() # 异步 告诉操作系统创建一个新的进程 并在该进程中执行task函数 # task() # 同步 print('主')
进程间的数据隔离
"""各进程之间开启后的数据只能在该进程内生效,无法生效到其他进程"""
from multiprocessing import Process import time money = 1000 def task(): global money money = 666 print('子进程的task函数查看money',money) if __name__ == '__main__': p1 = Process(target=task) p1.start() # 创建子进程 time.sleep(3) # 主进程代码等待3s print(money) # 主进程代码打印money
结果:
进程的join方法
from multiprocessing import Process import time def task(name,n): print('%s is running' % name) time.sleep(n) print('%s is over' % name) if __name__ == '__main__': p1 = Process(target=task, args=('jason1', 1)) p2 = Process(target=task, args=('jason2', 2)) p3 = Process(target=task, args=('jason3', 3)) # 主进程代码会在子进程代码运行结束后再去执行 start_time = time.time() p1.start() p1.join() # join使用的位置不同,代码的执行就不同 p2.start() p2.join() p3.start() p3.join() print(time.time() - start_time) # 结果是6s多,原因是每次执行昂完当前任务才会执行下一个 # 所有进程同时进行 start_time = time.time() p1.start() p2.start() p3.start() p1.join() # join使用的位置不同,代码的执行就不同 p2.join() p3.join() print(time.time() - start_time) # 结果是3s多,开启所有进程运行,最后完成的进程就是全部花费的时间
IPC机制
IPC机制: 指的是进程间的通信机制 消息队列: 存储数据的地方,所有人都可以进行数据的存取 from multiprocessing import Queue """"队列:先进先出""" q = Queue(3) # 括号内指定的是存储数据的个数 q.put(111) # 队列中存入数据 print(q.full()) # 判断队列是否已经满了 q.put(222) q.put(333) print(q.full()) print(q.get()) # 从队列中取出数据 print(q.empty())# 判断队列是否为空 print(q.get()) print(q.get()) print(q.get_nowait()) # 自定义异常,使其变为阻塞 """full()和empty()在多进程中都不能使用""" from multiprocessing import Process,Queue def product(q): q.put('子进程p添加的数据') def consumer(q): print('子进程获取队列中的数据',q.get()) if __name__ == '__main__': q = Queue() # 主进程往队列中添加数据 p1 = Process(target=consumer,args=(q,)) p2 = Process(target=product,args=(q,)) p1.start() p2.start() print('主进程')
生产者消费者模型
生产者: 负责产生数据的'人' 消费者: 负责处理数据的'人' 该模型除了有生产者和消费者之外还必须有消息队列(只要是能够提供数据保存服务和提取服务的理论上都可以)
进程对象的多种方法
# 1.如何查看进程号 from multiprocessing import Process, current_process current_process() current_process().pid import os os.getpid() os.getppid() # 2.终止进程 p1.terminate() ps:计算机操作系统都有对应的命令可以直接杀死进程 # 3.判断进程是否存活 p1.is_alive() # 4.start() # 5.join()
守护进程
# 守护进程会随着守护的进程结束而立刻结束 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=('1',)) p.daemon = True # 此代码将子进程设置为守护进程:主进程代码结束,子进程立刻结束。且必须在start之前执行 p.start() print('预言家被刀出局!!!')
孤儿进程与僵尸进程
僵尸进程: 进程已经运行结束 但是相关的资源并没有完全清空
需要父进程参与回收
孤儿进程: 父进程意外死亡 子进程正常运行 该子进程就称之为孤儿进程
孤儿进程也不是没有人管 操作系统会自动分配资源接收
多进程数据错乱问题
# 1. 多进程操作数据很可能会造成数据错乱>>>:互斥锁 # 2. 互斥锁:将并发变成串行,牺牲了效率但是保障了数据的安全 """模拟12306""" from multiprocessing import Process import time import json import random # 查票 def search(name): with open(r'data.json', 'r', encoding='utf8') as f: data = json.load(f) print('%s在查票 当前余票为:%s' % (name, data.get('ticket_num'))) # 买票 def buy(name): # 再次确认票 with open(r'data.json', 'r', encoding='utf8') as f: data = json.load(f) # 模拟网络延迟 time.sleep(random.randint(1, 3)) # 判断是否有票 有就买 if data.get('ticket_num') > 0: data['ticket_num'] -= 1 with open(r'data.json', 'w', encoding='utf8') as f: json.dump(data, f) print('%s买票成功' % name) else: print('%s很倒霉 没有抢到票' % name) def run(name): search(name) buy(name) if __name__ == '__main__': for i in range(10): p = Process(target=run, args=('用户%s' % i,)) p.start()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律