python学习Day41
Day 41
今日内容概要
- 创建进程的多种方式(需掌握)
- join方法
- 进程间数据默认隔离
- 进程间通信(IPC机制)
- 生产者与消费者模型
- 进程相关方法
- 守护进程
- 僵尸进程与孤儿进程
- 互斥锁(重要)
今日内容详细
1.创建进程的多种方式(需掌握)
1.双击桌面程序图标
2.代码创建进程(需掌握)
————————————————————————————————————————————————
方式一:
from multiprocessing import Process#多进程模块
import time
def task(name):
print(f'{name}正在运行')
time.sleep(3)
print(f'{name}运行结束')
if __name__ == '__main__':
'同步操作'
# task('jason')#执行函数
# print('主进程')
#运行结果:jason正在运行 (睡三秒) jason运行结束 主进程
'异步操作'
p=Process(target=task,args=('jason',))#创建一个进程对象
p.start()#告诉操作系统创建一个进程(创建一个子进程去执行task(),主进程继续往下执行)
print('主进程')
# 运行结果:主进程 jason正在运行 (睡三秒) jason运行结束
"""
不同操作系统创建进程代码底层原理不同
windows:类似于导模块,必须有__main__启动脚本
mac、linux:类似于直接拷贝,不需要__main__启动脚本,但是为了为了兼容性可以加上
"""
—————————————————————————————————————————————————
方式二:(利用面向对象的方式)
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(3)
print(f'{self.name}运行结束')
if __name__ == '__main__':
obj=MyProcess('jason')
obj.start()
print('主进程')
#运行结果:主进程 jason正在运行 (睡三秒) jason运行结束
2.join方法
join:让主进程等待子进程运行结束后再运行
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=('jason',))
p.start()
p.join()#让主进程最后执行
print('主进程')
#运行结果:jason正在运行 jason运行结束 主进程
#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=('jason',1))
p2=Process(target=task,args=('torry',2))
p3=Process(target=task,args=('kiven',3))
start_time=time.time()
#p1.start()
#p1.join()
#p2.start()
#p2.join()
#p3.start()
#p3.join()
#end_time=time.time()-start_time
#print(f'总耗时:{end_time}')#耗时6秒多
#print('主进程')
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
end_time=time.time()-start_time
print(f'总耗时:{end_time}')#耗时3秒多
print('主进程')
3.进程间数据默认隔离
多个进程数据彼此之间默认是互相隔离的
#如果想进程间通信需要借助'管道'或'队列'
from multiprocessing import Process
money = 100
def task():
global money
money = 666
print('子进程打印的money',money)#666
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join()
print('父进程打印的money',money)#100
#运行结果:子进程打印的money 666 父进程打印的money 100
4.进程间通信(IPC机制)
进程间通信需要借助 “ 管道 ” 或 “ 队列 ”
储备知识:
队列:先进先出
from multiprocessing import Queue
#1.创建队列对象
q=Queue(2)#队列中可以容纳3个数据,不写默认2147483647个
#2.往队列添加数据
q.put(111)
q.put(222)
#2.1判断队列是否已存满
print(q.full())#True
# q.put(444)#超出数据存放极限时程序进入阻塞态,直到队列中有数据被取出
#3.从队列中提取数据
print(q.get())#111
print(q.get())#222
#3.1判断队列是否已取空
print(q.empty())#True
# print(q.get())#超出数据获取极限时程序进入阻塞态,直到队列中有数据被添加,
#4.队列中如果没有数据可取则直接报错
print(q.get_nowait())#111
print(q.get_nowait())#222
print(q.get_nowait())#直接报错
"""
q.put() 往队列添加数据
q.get() 从队列中提取数据
___以下三个方法在多进程下不能准确使用__
(可能刚判断存满,另一个进程里就往队列中添加了数据)
q.full() 判断队列是否已存满
q.empty() 判断队列是否已取空
q.get_nowait 队列中如果没有数据可取则直接报错
"""
进程间通信的IPC机制
1.主进程与子进程通信
2.子进程与子进程通信
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('主进程')
#运行结果:主进程 子进程的consumer从队列中获取数据 子进程procedure往队列中添加了数据
5.生产者与消费者模型
生产者: 产生/获取数据
消费者: 处理数据
eg: 爬取红牛分公司
生产者:获取网页数据的代码(函数)
爬出数据
消费者:从网页数据中筛选出符合条件的数据(函数)
筛选
完整的生产者消费者模型至少有三个部分
生产者
消息队列/数据库 (做中间存放数据)
消费者
6.进程相关方法
1.查看进程号
方法1:
from multiprocessing import current_process
current_process().pid#获取当前进程的进程号
方法2:
import os
os.getpid()#获取当前进程的进程号
方法3:
import os
os.getppid()#获取当前进程的父进程的进程号
2.结束进程
p1.terminate()#结束p1进程
3.判断进程是否存活
p1.is_alive()
#如果又要让操作系统创建进程,又要结束进程,还要判断是否存活 时间太短可能反应不过来导致判断有误,这个时候只要给系统添加time.sleep()一点时间 就可以得出准确判断
7.守护进程
如何理解守护
伴随着守护对象的存活而存活 死亡而死亡
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=('子进程',))
p.daemon = True # 将子进程设置为守护进程:主进程代码结束 子进程立刻结束
p.start()
print('主进程没了')
#运行结果:主进程没了
8.僵尸进程与孤儿进程
僵尸进程:
进程已经运行结束 但是相关资源没有完全清空
需要父进程参与回收
孤儿进程:
父进程以外结束 子进程正常运行 该子进程就称为孤儿进程
孤儿进程也不是没人回收,操作系统会自动分配类似父进程的来回收
9.互斥锁(重要)
模拟抢票:
#抢票时有两个阶段:查票 买票
#买票时也有两个阶段:查票 买票
'当我12点打开12306准备抢票时显示还有20张,过了半小时我再点买票时后台会查看12:30还有没有票 如果此时有则买票,没有则返回无'
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()
#思考如何优化
作业
1.整理今日内容及博客
2.尝试将TCP服务端制作成并发效果
客户端服务端全部设置成自动发消息自动回消息
eg: 客户端发hello 服务端直接转大写回HELLO
3.思考如何让抢票符合日常逻辑
4.准备选课系统考试