线程 、进程、协程的基本使用
进程(Process)、线程(Thread)、协程(Coroutine)的概念:
进程:
就是正在运行的程序,它是操作系统中,资源分配的最小单位.,
资源分配:分配的是cpu和内存等物理资源。
进程号是进程的唯一标识。
默认情况下一个进程只有一个线程,在进程里面可以创建多个线程。
线程:
cpu执行程序的最小单位, 通过线程去执行进程中代码, 线程是执行代码的分支,
线程是依附在进程里面的, 没有进程就没有线程,
同一个程序执行两次之后是两个进程
进程和进程之间的关系: 数据彼此隔离,通过socket通信
协程:
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
协程在子程序内部可中断的,然后转而执行别的子程序,在适当的时候再返回来接着执行。
并行和并发
- 并发:一个cpu同一时间不停执行多个程序
- 并行:多个cpu同一时间不停执行多个程序
同步和异步
- 同步是指代在程序执行多个任务时,按部就班的依次执行,必须上一个任务执行完有了结果以后,才会执行下一个任务。
- 异步是指代在程序执行多个任务时,没有先后依序,可以同时执行,所以在执行上一个任务时不会等待结果,直接执行下一个任务。一般最终在下一个任务中通过状态的改变或者通知、回调的方式来获取上一个任务的执行结果。
cpu的进程调度方法
# 先来先服务fcfs(first come first server):先来的先执行
# 短作业优先算法:分配的cpu多,先把短的算完
# 时间片轮转算法:每一个任务就执行一个时间片的时间.然后就执行其他的.
# 多级反馈队列算法
越是时间长的,cpu分配的资源越少,优先级靠后
越是时间短的,cpu分配的资源越多
进程的性质:
- 进程之间的数据彼此隔离
- 多个进程之间是异步并发
–进程(Process):
进程的基本使用:
import os, time, random
from multiprocessing import Process
def func(n):
time.sleep(random.randrange(3))
print("数字{}<=>1.子进程id>>{},2父进程id>>{}".format(n, os.getpid(), os.getppid()))
if __name__ == "__main__":
for i in range(1, 11):
# 创建子进程,返回进程对象,执行func这个任务
p = Process(target=func, args=(i,)) # args=(i,)传递参数
# 调用子进程
p.start() # 可简写成 Process(target=func, args=(i,)).start()
print("主进程执行结束了....")
print(os.getpid()) # os.getpid()进程号
运行视图:
运行视图不唯一,因为多个进程之间是异步并发
进程的join 函数:
- join 等待当前子进程全部执行完毕之后,主进程在执行(用来同步子父进程的)
例:
p = Process(target=func,args=(i,))
p.join()
同步 异步 / 阻塞 非阻塞
- 同步:必须等我这件事干完了,你在干,只有一条主线,就是同步
- 异步:没等我这件事情干完,你就在干了,有两条主线,就是异步
- 阻塞:比如代码有了input,就是阻塞,必须要输入一个字符串,否则代码不往下执行
- 非阻塞:没有任何等待,正常代码往下执行.
- 同步阻塞 :效率低,cpu利用不充分
- 异步阻塞 :比如socketserver,可以同时连接多个,但是彼此都有recv
- 同步非阻塞:没有类似input的代码,从上到下执行.默认的正常情况代码
事件 (Event)
- 异步非阻塞:效率是最高的,cpu过度充分,过度发热 液冷
事件 (Event)阻塞事件 :
‘’’
e = Event()生成事件对象e
e.wait()动态给程序加阻塞 , 程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值是False]
# 如果是True 不加阻塞
# 如果是False 加阻塞
# 阻塞事件 :
e = Event()生成事件对象e
e.wait()动态给程序加阻塞 , 程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值是False]
# 如果是True 不加阻塞
# 如果是False 加阻塞
# 控制这个属性的值
# set()方法 将这个属性的值改成True
# clear()方法 将这个属性的值改成False
# is_set()方法 判断当前的属性是否为True (默认上来是False)
Event_test.py:
在这里插入代码片
控制这个属性的值
# set()方法 将这个属性的值改成True
# clear()方法 将这个属性的值改成False
# is_set()方法 判断当前的属性是否为True (默认上来是False)
在这里插入代码片
场景在多任务当中
同步:必须等我这件事干完了,你在干,只有一条主线,就是同步
异步:没等我这件事情干完,你就在干了,有两条主线,就是异步
阻塞:比如代码有了input,就是阻塞,必须要输入一个字符串,否则代码不往下执行
非阻塞:没有任何等待,正常代码往下执行.
# 同步阻塞 :效率低,cpu利用不充分
# 异步阻塞 :比如socketserver,可以同时连接多个,但是彼此都有recv
# 同步非阻塞:没有类似input的代码,从上到下执行.默认的正常情况代码
# 异步非阻塞:效率是最高的,cpu过度充分,过度发热 液冷
守护进程
守护进程守护的是主进程,如果主进程中的所有代码执行完毕了,
当前这个守护进程会被立刻杀死,立刻终止.
语法:
进程.daemon = True 设置当前这个进程为守护进程
必须写在start()调用进程之前进行设置
默认:主进程会默认等待所有子进程执行结束之后,在关闭程序,释放资源
代码:
from multiprocessing import Process
import time
# (3) 守护进程实际用途: 监控报活
# 守护进行
def alive():
while True:
print("给监控的总服务器发消息,报告自己的存活状态, i am alive~")
time.sleep(1)
# 执行任务
def func():
while True:
try:
time.sleep(1)
raise RuntimeError
print("当前5号服务器功能:对日志进行数据分析.... ")
except:
break
# pass
if __name__ == "__main__":
# 创建2个子进程
p1 = Process(target=alive)
p2 = Process(target=func)
# 设置p1为守护进程
# p1.daemon = True
p1.start()
p2.start()
# 必须等到p2任务执行结束之后,在向下执行.
p2.join()
print("当前服务器状态异常 ... ")
没有设置守护进程视图:
设置守护进程视图:
#可以给子进程贴上守护进程的名字,该进程会随着主进程代码执行完毕而结束(为主进程守护)
(1)守护进程会在主进程代码执行结束后就终止
(2)守护进程内无法再开启子进程,否则抛出异常(了解)
锁(Lock)
上锁和解锁是一对,只上锁不解锁会发生死锁现象(代码阻塞,不往下执行了)
互斥锁 : 互斥锁是进程之间的互相排斥,谁先抢到这个锁资源就先使用,后抢到后使用
信号量:Semaphore 本质上就是锁,只不过可以控制上锁的数量
look:
lock.acquire()# 上锁
lock.release()# 解锁
# 创建一把锁
lock = Lock()
# 上锁
lock.acquire()
# 连续上锁不解锁是死锁
# lock.acquire() error
print("厕所中...")
# 解锁
lock.release()
print("执行程序 ... ")
Semaphore:
from multiprocessing import Semaphore,Process
import time,random
sem = Semaphore(4)
sem.acquire()
# sem.acquire()
# sem.acquire()
# sem.acquire()
# sem.acquire() # 上第五把锁出现死锁状态.
print("执行响应的操作")
sem.release()
"""
# 总结:
Semaphore 可以设置上锁的数量
同一时间最多允许几个进程上锁
创建进程的时候,是异步并发
执行任务的时候,遇到锁会变成同步程序.
"""
lock.acquire()# 上锁
lock.release()# 解锁
#同一时间允许一个进程上一把锁 就是Lock
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲速度却保证了数据安全。
#同一时间允许多个进程上多把锁 就是[信号量Semaphore]
信号量是锁的变形: 实际实现是 计数器 + 锁,同时允许多个进程上锁
# 互斥锁Lock : 互斥锁就是进程的互相排斥,谁先抢到资源,谁就上锁改资源内容,为了保证数据的同步性
# 注意:多个锁一起上,不开锁,会造成死锁.上锁和解锁是一对.
事件(Event)
# 阻塞事件 :
e = Event()生成事件对象e
e.wait()动态给程序加阻塞 , 程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值是False]
# 如果是True 不加阻塞
# 如果是False 加阻塞
# 控制这个属性的值
# set()方法 将这个属性的值改成True
# clear()方法 将这个属性的值改成False
# is_set()方法 判断当前的属性是否为True (默认上来是False)
进程间通信 IPC
# IPC Inter-Process Communication
# 实现进程之间通信的两种机制:
# 管道 Pipe
# 队列 Queue
# put() 存放
# get() 获取
# get_nowait() 拿不到报异常
# put_nowait() 非阻塞版本的put
q.empty() 检测是否为空 (了解)
q.full() 检测是否已经存满 (了解)
–线程(Thread)
生产者与消费者模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYUQwS07-1611230808561)(assets/生产者消费者.png)]