内容概要
-
并发编程理论与操作系统发展史
-
多道技术
-
近程理论及调度算法
内容概要 -
同步与异步
-
阻塞与非阻塞
-
创建进程的两种方式
-
进程join方法
-
进程间数据隔离
-
进程间通信之IPC机制
-
进程对象诸多方法
-
生产者消费者模型
-
互斥锁
并发编程理论
'''在计算机中主要是cpu进行工作'''
操作系统发展史
1.穿孔卡片阶段
计算机很庞大 使用很麻烦 一次只能给一个人使用 期间很多时候计算机都不工作
好处:程序员独占计算机 为所欲为
坏处:计算机利用率太低 浪费资源
2.联机批处理系统
提前使用磁带一次性录入多个程序员编写的程序 然后交给计算机执行
CPU工作效率有所提升 不用反复等待程序录入
3.脱机批处理系统
极大地提升了CPU的利用率
总结:CPU提升利用率的过程
多道技术
'''在学习并发编程的过程中 不做可以提醒的情况下,默认一台计算机就只有一个cpu'''
# 单道技术
所有的程序排队执行 过程中不能重合
# 多道技术
利用空闲时间提前准备其他数据 最大化提升CPU利用率
# 多道技术详细
1.切换
计算机的CPU在两种情况下会切换(不让你用 给别人用)
1.程序有IO操作
输入\输出操作
input、time.sleep、read、write
2.程序长时间占用CPU
我们得雨露均沾 让多个程序都能被CPU运行一下
2.保存状态
CPU每次切换走之前都需要保存当前操作的状态 下次切换回来基于上次的进度继续执行
近程理论
进程与程序的区别
程序:一堆死代码(还没有被运行起来)
进程:正在运行的程序(被运行起来了)
进程的调度算法(重要)
1.FCFS(先来先服务)
对短作业不友好
2.短作业优先调度
对长作业不友好
3.时间片轮转法+多级反馈队列(目前还在用)
将时间均分 然后根据进程时间长短再分多个等级
等级越靠下表示耗时越长 每次分到的时间越多 但是优先级越低
进程的并行与并发
并行
多个进程同时执行 必须要有多个CPU参与 单个CPU无法实现并行
并发
多个进程看上去像同时执行 单个CPU可以实现 多个CPU肯定也可以
进程的三状态
就绪态
所有的进程在被CPU执行之前都必须先进入就绪态等待
运行态
CPU正在执行
阻塞态
进程运行过程中出现了IO操作 阻塞态无法直接进入运行态 需要先进入就绪态
同步与异步
同步与异步是用来表达任务的提交方式
1.同步
提交完任务后原地等待任务的返回结果,期间不做任何事情
2.异步
提交完任务之后不原地等待任务的返回结果,直接去做其他事情,有结果自动通知
阻塞与非阻塞是用来表示任务的执行状态的
阻塞
阻塞态
非阻塞
就绪态、运行态
# 阻塞与非阻塞 一般与 同步异步 一起综合使用
同步阻塞>>>>>>>>>效率最低
同步非阻塞
异步阻塞
异步非阻塞>>>>>>>效率最高
创建进程的多种方式
"""
1.在桌面双击软件图标,创建进程
2.使用python代码创建进程
在不同的操作系统中创建进程底层原理不一样
windows
以导入模块的形式创建进程
linux/mac
以拷贝代码的形式创建进程
"""
from multiprocessing import Process
def task(num):
print(f'{num}开始表演~')
# 由于windows系统在创建进程的时候会单独开辟一个空间去运行进程代码
# 以导入模块的形式创建进程
# 这样的话这个空间会运行到创建进程的这行代码
# 就相当于一直在重复的创建进程,所以会报错
# 我们就可以通过__name__来限制他,如果他不是执行文件的话就不会运行 if __name__ == '__main__': 下面的代码
if __name__ == '__main__':
# Process 创建进程,通过 target指定子进程执行的任务是task函数
# 由于task需要传参,在创建子进程的时候通过args传参数给子进程中的task函数
# 这样就实现了进程的创建
p = Process(target=task, args=('牛牛',)) # 创建进程对象
p.start() # 子进程执行(异步操作)
进程对象的多种方法
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()
进程间的join方法
from multiprocessing import Process
import time
def thing(name, age, num):
print(f'''
姓名:{name} 年龄:{age} 正在子进程中跑
''')
time.sleep(num)
print(f'{name}跑完了')
if __name__ == '__main__':
p1 = Process(target=thing, args=('小明', 18, 1))
p2 = Process(target=thing, args=('小李', 19, 2))
p3 = Process(target=thing, args=('小白', 20, 3))
start_time = time.time()
# p.start() # 异步
'''主进程代码等待子进程代码运行结束再执行'''
# p.join()
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
end_time = time.time()
print(f'''主程序运行时间为: {end_time - start_time} 秒''')
# 3s 多一些, 这是因为在p1.join的时候别的程序也在进行,所以是3s,但是如果将各自的join方法放在各自.start()方法下面的话就会变成6s多
进程间数据隔离
# 同一台计算机上的多个进程数据是严格意义上的物理隔离(默认情况下)
from multiprocessing import Process
num = 1000
def task():
global num
# 虽然这边是global可以修改全局变量,
# 但是这是修改子进程中的全局变量,与主进程无关
num = 666
print(f'子进程中的Num为:{num}')
if __name__ == '__main__':
p = Process(target=task)
p.start() # 异步运行task 命令~
print(f'主进程中的num为:{num}')
# 打印结果为1000 这也证明了
# 子进程中的数据修改和主进程中的数据是无关的
IPC机制
IPC=进程间通信
1.消息队列:
消息队列:存储数据的地方 所有人都可以存,也可以取
from multiprocessing import Queue
q = Queue() # 括号内能指定存储数据的个数,默认为:2147483647
队列:先进先出 堆栈:先进后出
我使用Put 放置了三个数据,取了四次,程序就会等什么时候又出现了数据,等待取出
反之放置了4个数据,直接运行,队列就会等第一个出去的数据,而并不会报错
消息队列方法
from multiprocessing import Queue
q = Queue() # 产生消息队列对象,括号内能指定存储数据的个数,默认为:2147483647
q.put() # 存放数据
q.get() # 取数据
q.empty() # 判断队列是否为空
q.full() # 判断队列是否已满
"""
full() empty() 在多进程中都不能使用!!!
"""
生产者消费者模型
生产者
负责产生数据的'人'
消费者
负责处理数据的'人'
该模型除了又生产者和消费者之外还必须有消息队列
(只要是能够提供数据和保存服务和提取服务的理论上都可以)
守护进程
守护进程会随着守护的进程结束而立刻结束
import time
from multiprocessing import Process
def run(name):
print(f'你好{name}!!')
time.sleep(3)
print(f'你好{name}!!')
if __name__ == '__main__':
p1 = Process(target=run, args=('小明',))
p1.daemon = True # 修改daemon的状态为True 就代表着 p1进程为主进程的守护进程,如果主进程运行完毕,子进程立即结束运行
p1.start()
time.sleep(1)
print('我要结束了!!')
僵尸进程与孤儿进程
僵尸进程
进程执行完毕之后并不会立刻销毁所有的数据,可能会有一些信息短暂的保留下来
# 进程号、进程执行时间、进程所消耗功率等等...
# 所有的进程都会变成僵尸进程
孤儿进程
子进程正常运行 父进程意外死亡 操作系统针对孤儿进程会派遣一个程序去管理他
多进程数据错乱问题
模拟抢票软件
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('%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()
"""
多进程操作数据很可能会造成数据错乱>>>:互斥锁
互斥锁
将并发变成串行 牺牲了效率但是保障了数据的安全
"""
标签:__,name,编程,并发,time,进程,import,CPU
From: https://www.cnblogs.com/ddsuifeng/p/16904846.html