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.准备选课系统考试
posted @ 2022-08-09 21:18  逢诱  阅读(20)  评论(0)    收藏  举报