今日内容概要
- 同步与异步
- 阻塞与非阻塞
- 创建进程的多种方式
- 进程间的数据隔离
- 进程的join方法
- IPC机制
- 生产者与消费者模型
- 进程对象的多种方法
- 守护进程
- 僵尸进程与孤儿进程
- 多进程数据错乱问题
今日内容详细
同步与异步
用来表达任务的提交方式
同步
	提交完任务之后原地等待任务的返回结果 期间不做任何事情
异步
	提交完任务之后不原地等待任务的返回结果 直接去做其他事 有结果自动通知
阻塞与非阻塞
用来表达任务的执行状态
阻塞
	阻塞态
非阻塞
	就绪态  运行态
综合使用
同步阻塞
同步非阻塞
异步阻塞
异步非阻塞(*****)
	效率最高
创建进程的多种方式
'''
1.鼠标双击软件图标
2.python代码创建进程
'''
'''第一种方式'''
from multiprocessing import Process
import time
def task(name):
    print('task is running', name)
    time.sleep(3)
    print('task is over', name)
    
'''
在不同的操作系统中创建进程底层原理不一样
	Windows
		以导入模块的形式创建进程
	Linux/Mac
		以拷贝代码的形式创建进程
'''
if __name__ == '__main__':
    p1 = Process(target=task, args=('jason',))  # 位置参数
    # p1 = Process(target=task, kwargs={'name':'jason'}) # 关键字参数
    p1.start()  # 异步 告诉操作系统创建一个新的进程 并在该进程中执行task函数
    print('主进程')
    
'''第二种方式'''
from multiprocessing import Process
import time
class MyProcess(Process):
    def __init__(self, name, age):
        super().__inin__()
        self.name = name
        self.age = age
        
    def run(self):
        print('run is running', self.name)
        time.sleep(3)
        print('run is over', self.age)
        
if __name__ == '__main__':
    obj = MyProcess('jason', 18)
    obj.start()
    print('主进程')
进程间数据隔离
同一台计算机上的多个进程数据是严格意义上的物理隔离(默认情况下)
'''做验证'''
from multiprocessing import Process
import time
money = 1000
def task():
    global money
    money = 888
    print('子进程的task函数查看money', money)
    
    
if __name__ == '__main__':
    p1 = Process(target=task)
    p1.start()  # 创建子进程
    time.sleep(3)  # 主进程代码等待3秒
    print(money)   # 主进程代码打印money
进程的join方法
'''主进程代码等待子进程代码运行结束再执行'''
from multiprocessing import Process
import time
def task(name, n):
    print(f'{name} is running')
    time.sleep(n)
    print(f'{name} is over')
 
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()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    print(time.time() - start_time)  # 3秒多
    # 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()
    # p2.start()
    # p2.join()
    # p3.start()
    # p3.join()
    # print(time.time() - start_time)  # 6秒多
IPC机制
IPC:进程间通信
消息队列:存储数据的地方 所有人都可以存 也都可以取
from multiprocessing import Queue
q = Queue(3)  # 括号内可以指定存储数据的个数
q.put(111)  # 往消息队列中存放数据
print(q.full())  # 判断消息队列是否已满  False
q.put(222)
q.put(333)
print(q.full())  # True
print(q.get())  # 111  从消息队列中取出数据  先进先出
print(q.get())  # 222
print(q.empty())  # 判断消息队列是否为空
print(q.get())   # 333
print(q.empty())  # True
'''
full()  empty()  在多进程中都不能使用 不准确 
可能一个进程刚判断消息队列为空 结果同一时间另一个进程又放进了数据
'''
'''不同进程之间读写数据'''
from multiprocessing import Process, Queue
def process1(q):
    q.put('子进程process1添加的数据')
    
    
def process2(q):
    print('子进程process2获取队列中的数据', q.get())
    
    
if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=process1, args(q,))
    p2 = Process(target=process2, args(q,))
    p1.start()
    p2.start()
    print('主进程')
生产者消费者模型
生产者
	负责产生数据的'人'
消费者
	负责处理数据的'人'
该模型除了有生产者和消费者之外还必须有消息队列(只要是能够提供数据保存服务和提取服务的理论上都可以)
进程对象的多种方法
1.如何查看进程号
	from multiprocessing import Process, current_process
	courrent_process()
	courrent_process().pid
	import os
	os.getpid()
	os.getppid()  # 查看当前进程的父进程
2.终止进程
	p1 = Process()
	p1.terminate()
	计算机操作系统都有对应的命令可以直接杀死进程
3.判断进程是否存活
	p1.is_alive()
4.start()
5.join()
守护进程
守护进程会随着守护的进程结束而立刻结束
如:
	进程1是进程2的守护进程 一旦进程1嗝屁 进程2也立刻嗝屁
from multiprocessing import Process
import time
def task(name):
    print(f'德邦总管{name}')
    time.sleep(3)
    print(f'德邦总管{name}')
    
    
if __name__ == '__main__':
    p1 = Process(target=task, args=('皇子',))
    p1.daemon = True  # 将p1设为主进程的守护进程
    p1.start()
    time.sleep(1)
    print('皇子嗝屁了')
僵尸进程与孤儿进程
僵尸进程
	进程执行完毕后并不会立刻销毁所有的数据 会有一些信息短暂的保留下来
	比如进程号 进程执行时间 进程消耗功率等给父进程查看
	ps:所有的进程都会变成僵尸进程
孤儿进程
	子进程正常运行 父进程意外死亡 操作系统针对孤儿进程会派遣福利院管理
多进程数据错乱问题
模拟抢票软件
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(f'{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(f'{name}买票成功')
    else:
        print(f'{name}很倒霉 没抢到票')
        
def run(name):
    search(name)
    buy(name)
    
    
if __name__ == '__main__':
    for i in range(10):
        p = Process(target=run, args=(f'用户{i}',))
        p.start()
        
        
'''
多进程操作数据很可能会造成数据错乱>>>:互斥锁
	互斥锁
		将并发变成串行 牺牲了效率但是保障了数据的安全
'''