并发01--进程01:操作系统发展过程、进程介绍
1.操作系统的发展史
# 其实主要就是围绕CPU的利用率问题
1.穿孔卡片 2.联机批处理系统 3. 脱机批处理系统
2.多道技术
# 单核实现并发的效果
并发:看起来像同时运行的就可以叫做并发,伪并行
并行: 真正意义的同时运行
ps:明星出轨>>>星轨(指微博能承受的并发量)
空间复用:空间上,多个程序公用一套计算机硬件
时间复用:时间上,切换+保存状态 (多个任务之间快速切换执行,感觉上是同时执行)
# 切换分为两种
1.当一个程序遇到IO操作时,操作系统会立刻剥夺该程序的cpu执行权限
(提高了CPU的利用率,并且不影响该程序的执行效率)
2.当一个程序长时间占用cpu,操作系统也会离开剥夺该程序的cpu执行权限
(提高了cpu的利用率,但降低了该程序的执行效率,实现了并发的效果)
3.进程
"""
程序就是一堆死代码 死的
进程则是正在执行的程序 活动 (就是程序的实例)
"""
# 进程的调度算法
先来先服务调度算法
短作业优先调度算法
时间片乱转法 + 多级反馈队列
3.1 进程运行的三状态图
就绪态:一切程序必须要先过就绪态才能加入运行态
运行态:正在被cpu执行
堵塞态:程序遇到IO操作了
理想:我们希望我开发的程序一直处于就绪态与运行态之间
3.2 两对重要概念
- 同步与异步
"""任务的提交方式"""
同步:任务提交后,原地等待任务的返回结果期间不做任何事情
异步:任务提交后,不原地等待任务的返回结果,继续执行下一行代码
结果由异步回调机制做处理
- 阻塞与非阻塞
"""程序的运行状态"""
阻塞:阻塞态
非阻塞:就绪态、运行态
上面的两队概念通常会组合出现,但最高效常用的就是异步非阻塞。
# 1. 同步与异步针对的是函数/任务的调用方式:
同步就是当一个进程发起一个函数(任务)调用的时候,一直等到函数(任务)完成,而进程继续处于激活状态。
而异步情况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行当,
函数返回的时候通过状态、通知、事件等方式通知进程任务完成。
# 2. 阻塞与非阻塞针对的是进程或线程:
阻塞是当请求不能满足的时候就将进程挂起,而非阻塞则不会阻塞当前进程
3.3 开启进程的两种方式
3.3.1 利用 multiprocessing 模块下的 Process 类
代码开启进程和线程的方式,代码书写基本是一样的。
# 第一种,函数式(必须掌握)
from multiprocessing import Process
import time
def task(name):
print('{} is running'.format(name))
time.sleep(3)
print('{} is over'.format(name))
再多建/新建一个进程,就相当于你现在执行的程序代码,复制一份,在内存中 新建一块空间来执行。
# 重点:
windows 操作系统下,创建进程一定要在main内创建,
因为windows下创建进程类似导入模块的方式,会从上往下依次执行代码,
若不在main内中创建,就会一直处于创建进程的死循环中。
# 例如: 不在main中创建进程,而在这里创建进程,
在这里的话,代码读取在这个位置后,就会去建新的进程,
然后新的进程又会执行该代码(代码跟这个完全一样,是复制的)
所以新的进程读取到这里,又再会去新建一个进程,产生一个一直在建新的进程的 死循环中。
# 故所有的执行代码,调用函数,或者实例化对象的时候,都将代码放在main中
# main内代码只会在本脚本程序在执行时调用,而在作为模块导入时,不会执行
if __name__ == '__main__':
# 1.实例化 Process 进程类的对象,
# 参数 target= 执行函数,注意执行函数不能调用,不能加()
# 参数 args=(),()内 以元祖的方式 传递 该执行函数的参数
p = Process(target=task, args=('jason',))
# 容器类型哪怕只有1个元素,一定也要用逗号隔开。防止出现小bug
# 2.开启进程
p.start() # 告诉操作系统,开始创建一个进程。
# 模拟执行其他代码
print('主')
# 执行结果:
主 由 当前代码 执行的结果
jason is running 由 新的进程打印出来的
jason is over
# 根据执行结果:
先打印了print('主'), 再打印了p.start()的返回结果。
说明 p.start() 开启进程这一步,是一个异步操作。
因为按照代码执行顺序下来,p.start() 在 print('主' )之前,
但是并没有等到 p.start() 的返回结果后,CPU就先打印了print('主')。
# 第二种,类继承式
from multiprocessing import Process
import time
class Myprocess(Process):
def __init__(self, name1):
super().__init__()
self.name1 = name1
def run(self):
print('{} is running'.format(self.name1))
time.sleep(3)
print('{} is over'.format(self.name1))
if __name__ == '__main__':
p = Myprocess('jason')
p.start()
print('主')
# 类的继承方式,将进程需要执行的函数,写在 run()中,覆盖父类 Process的run方法,
# 若是有参数,需要定义在实例化 构造函数 __init__(self,arg) -----> arg:参数变量名
3.3.2 方法介绍
p.start(): # 启动进程,并调用该子进程中的p.run()
p.run(): # 进程启动时运行的方法,正是它去调用target指定的函数
我们自定义类的类中一定要实现该方法
p.terminate(): # 强制终止进程p,但不会进行任何清理操作
如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。
如果p还保存了一个锁,那么也将不会被释放,进而导致死锁
p.is_alive(): # 如果p仍然运行,返回True
p.join([timeout]): # 主线程等待p终止
强调:是主线程处于等的状态,而p是处于运行的状态
timeout是可选的超时时间
需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
# 开启进程:p.start() 或 p.run()
3.3.3 属性介绍
p.daemon: # 设置p为守护进程 默认值为False,
如果设为True,代表p为后台运行的守护进程,
当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程
必须在p.start()之前设置
p.name: # 进程的名称
p.pid: # 进程的pid
p.exitcode: # 进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
p.authkey: # 进程的身份验证键
默认是由os.urandom()随机生成的32字符的字符串。
这个键的用途是为涉及网络连接的底层进程间通信提供安全性
这类连接只有在具有相同的身份验证键时才能成功(了解即可)
3.3.4 总结
# 创建进程就是在内存中申请一块内存空间将需要运行的代码丢进去
一个进程对应在内存中就是一块独立的内存空间
多个进程对应在内存中就是多块独立的内存空间
# 进程与进程之间数据默认情况下是无法直接交互的,如果想交互,可以借助于第三方工具、模块
3.4 join方法
join是让主进程等待子进程代码运行结束之后,再继续运行。不影响其他子进程的执行。
# 一个需求,等到子进程的结果返回后,再继续执行当前主进程的代码。
# 本例就是先打印 子进程 task()的结果,再打印 print('主')
from multiprocessing import Process
import time
# 案例三 (改写案例二)
def task(name, n):
print('{} is running'.format(name))
time.sleep(n)
print('{} is over'.format(name))
if __name__ == '__main__':
start_time = time.time()
# 先开启全部的子进程
p_list = []
for i in range(1, 4):
p = Process(target=task, args=('jason', i))
p.start()
p_list.append(p)
# 再将子进程全部join()
for p in p_list:
p.join()
# 当前主进程的执行代码
print('主', '运行时间:{}'.format(time.time() - start_time))
3.5 进程之间数据相互隔离的(默认情况下)
# 验证进程之间数据相互隔离
from multiprocessing import Process
money = 100
def task():
global money # 局部命名空间中,修改全局变量
money = 666
print('子进程中money:{}'.format(money))
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join()
print('主进程中money:{}'.format(money))
# 打印结果:
子进程中money:666
主进程中money:100
# 说明子进程中修改money的函数确实运行了,但是只是作用于子进程中,并没有修改到主进程的money。完成验证
ps:
# 作为一名python程序员当你遇到一个功能的时候,第一时间你可以考虑是否有对应的模块已经帮你实现功能
"""
人工智能相关参考资料:
聊天机器人(自动回复等):http://www.turingapi.com/
文字、人脸、图像识别:https://www.xfyun.cn/?ch=bd05&b_scene_zt=1
智能写诗等:http://ai.baidu.com/creation/main/demo
天行数据:https://www.tianapi.com/
"""