并发与并行
并行
只有多个CPU,才能实现并行;多个CPU同时执行任务(线程或者进程)
并发
CPU轮流执行任务,每个任务执行0.01s(举例),看起来是同时,实际上同一个时刻还是只执行一个任务;这种情况,称为并发;
线程 进程
线程
线程是CPU执行的最基本单元
进程
进程是系统进行分配资源和调度的基本单位,是操作系统执行的基本单元;
多线程相比多进程的优势
多线程无需重复申请资源,子线程和父线程共享资源;
多线程间的通信速度快于进程通信,效率更高;
协程
协程,又称微线程。在Python语言中,单线程+异步I/O的编程模型称为协程。协程的特点是只有一个线程在执行,只有当子程序内部发生阻塞或者IO时,才会交出线程执行权给其他子程序,适当的时候再返回;
协程相比多线程的优势
- 省去了大量线程切换的开销;
- 由于是单线程执行,共享资源不需要加锁,执行效率更高;
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(f"{delay}: {what}")
async def main():
task1 = asyncio.create_task(say_after(2, 'hello1'))
task2 = asyncio.create_task(say_after(2, 'world1'))
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello2')
await say_after(2, 'world2')
await task1
await task2
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
# started at 10:19:42
# 1: hello2
# 2: hello1
# 2: world1
# 2: world2
# finished at 10:19:45
要真正运行一个协程,asyncio 提供了三种主要机制:
-
asyncio.run()函数用来运行最高层级的入口点 “main()” 函数 -
等待一个协程。
await say_after(1, 'hello2')、await say_after(2, 'world2')会在等待 1 秒后打印 “hello2”,然后 再次 等待 2 2 2 秒后打印 “world2”: -
asyncio.create_task() 函数用来并发运行作为 asyncio 任务 的多个协程。
-
总用时 3 3 3s
死锁
两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
产生死锁的原因:
- 因为系统资源不足。
- 进程运行推进顺序不合适。
- 资源分配不当等。
死锁的必要条件
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
死锁的避免:
死锁的预防是通过破坏产生条件来阻止死锁的产生,但这种方法破坏了系统的并行性和并发性。
死锁产生的前三个条件是死锁产生的必要条件,也就是说要产生死锁必须具备的条件,而不是存在这3个条件就一定产生死锁,那么只要在逻辑上回避了第四个条件就可以避免死锁。避免死锁采用的是允许前三个条件存在,但通过合理的资源分配算法来确保永远不会形成环形等待的封闭进程链,从而避免死锁。该方法支持多个进程的并行执行,为了避免死锁,系统动态的确定是否分配一个资源给请求的进程。
银行家算法:分配资源之前先看清楚,资源分配后是否会导致系统死锁。如果会死锁,则不分配,否则就分配。要求每个进程必须先知道资源的最大需求量,且在系统运行过程中,考察每个进程对各类资源的申请需要花费较多的时间。
进程间通信方式:
管道、共享存储器系统、消息传递系统、信号量
mutex是互斥锁
1385

被折叠的 条评论
为什么被折叠?



