协程
协程和线程 #共同点: -线程和协程的创建,切换销毁都需要时间开销, -在cpython中线程和协程都不能利用多个cpu(只能并发) #不同点: -多线程线程的切换是由操作系统完成,而协程的切换是通过代码实现,操作系统不可见 -多线程创建,切换销毁时间开销较大,协程的时间开销很小,携程切换用户可操作性,不会增加操作系统压力
1
2
3
4
5
6
7#进程: 开销大,数据隔离,是cpu最小的资源分配单位,至少有一个线程,cpython可以并行 #线程: 开销小,数据共享,是cpu最小的调度单位,是进程的一部分,cpython下只可以并发
1
2
3
4互斥锁和递归锁 #相同点: 1.都是一种锁 2.都是为了解决数据安全隐患 #不同点: Lock-互斥锁 不能在一个线程中连续acquire,效率相对高 Rlock-递归锁 可以在一个线程中连续acquire,效率相对低
1
2
3
4
5
6
7#简述 进程、线程、协程的区别 以及应用场景? 进程:开销大,数据隔离,是cpu最小的资源分配单位,至少有一个线程,cpython可以并行,程序开启时就开启了一个进程 线程:开销小,数据共享,是cpu最小的调度单位,是进程的一部分,cpython下只可以并发 协程:开销小,不能并行,只能并发,可以使一个线程下的多个任务再碰见IO操作时,交替执行,提高效率 #应用场景: 程序的开启就开启了进程, 一个单独的子线程去做一件事,分析网页,没有什么io操作就可以单独开线程 大量任务等待去做要求一定的并发,而且有很多的IO操作就要尽可能使用协程
1
2
3
4
5
6
7
8# 操作系统 # 1.计算机中所有的资源都是由操作系统分配的 # 2.操作系统调度任务:时间分片、多道机制 # 3.CPU的利用率是我们努力的指标 # 并发 # 进程 开销大 数据隔离 资源分配单位 cpython下可以利用多核 # 进程的三状态:就绪 运行 阻塞 # multiprocessing模块 # Process-开启进程 # Lock - 互斥锁 # 为什么要在进程中加锁 # 因为进程操作文件也会发生数据不安全 # Queue -队列 IPC机制(Pipe,redis,memcache,rabbitmq,kafka) # 生产者消费者模型 # Manager - 提供数据共享机制 # 线程 开销小 数据共享 cpu调度单位 cpython下不能利用多核 # GIL锁 # 全局解释器锁 # Cpython解释器提供的 # 导致了一个进程中多个线程同一时刻只有一个线程能当问CPU -- 多线程不能利用多核 # threading # Thread类 - 能开启线程start,等待线程结束join # Lock-互斥锁 不能在一个线程中连续acquire,效率相对高 # Rlock-递归锁 可以在一个线程中连续acquire,效率相对低 # 死锁现象如何发生?如何避免? # 线程队列 queue模块 # Queue # LifoQueue # PriorityQueue # 池 # concurrent.futrues.ThreadPoolExecutor,ProcessPoolExecutor # 实例化一个池 tp = ThreadPoolExecutor(num),pp = ProcessPoolExecutor(num) # 提交任务到池中,返回一个对象 obj = tp.submit(func,arg1,arg2...) # 使用这个对象获取返回值 obj.result() # 回调函数 obj.add_done_callback(函调函数) # 阻塞等待池中的任务都结束 tp.shutdown() #协程全部! # 概念 # IO操作 # 同步异步 # 阻塞非阻塞 # 1.所有讲过的概念都记住 # 2.数据安全问题 # 3.数据隔离和通信 # 4.会用基本的进程 线程 池
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 1.协程的概念
- 能够在一个线程下的多个任务之间来回切换,那么每一个任务就是协程
![1558063115300](C:\Users\big cattle\AppData\Roaming\Typora\typora-user-images\1558063115300.png)
进程和线程的切换是由操作系统控制切换
协程和线程 #共同点: -线程和协程的创建,切换销毁都需要时间开销, -在cpython中线程和协程都不能利用多个cpu(只能并发) #不同点: -多线程线程的切换是由操作系统完成,而协程的切换是通过代码实现,操作系统不可见 -多线程创建,切换销毁时间开销较大,协程的时间开销很小,携程切换用户可操作性,不会增加操作系统压力
1
2
3
4
5
6
7
# 2.协程操作(模块)
线程切换
两种切换方式
两种切换方式 # 原生python完成 yield asyncio # C语言完成的python模块 greenlet gevent
1
2
3原生python代码实现 (asyncos 模块)- asyncos利用yield记录线程代码执行状态和位置,但是yield不能规避io操作
C语言完成的PYthon模块(#greenlet模块)
规避IO操作,切换原理(了解)
![1558067064860](C:\Users\big cattle\AppData\Roaming\Typora\typora-user-images\1558067064860.png)
# 2.1 gevent 第三方模块
基本格式
import time import gevent from gevent import monkey monkey.patch_all() #用mokey模块使协程识别多次使用的外部方法,比如time.time() def eat(): print('wusir is eating') time.sleep(1) print('wusir finished eat') def sleep(): print('小马哥 is sleeping') time.sleep(1) print('小马哥 finished sleep') # g1 = gevent.spawn(eat) # 创造一个协程任务 # g2 = gevent.spawn(sleep) # 创造一个协程任务 # print(g1.value) # print(g2.value) # # g1.join() # 阻塞 直到g1任务完成为止 # # g2.join() # 阻塞 直到g1任务完成为止 # gevent.joinall([g1,g2,g3]) #知道列表内的协程任务全部终止为止 g_l = [] for i in range(10): g = gevent.spawn(eat) g_l.append(g) gevent.joinall(g_l)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26接收返回值
value
# g1 = gevent.spawn(eat) # 创造一个协程任务 # g2 = gevent.spawn(sleep) # 创造一个协程任务 # print(g2.value)
1
2
3
# 2.2 asyncio 内置模块(记住启动一个/多个线程)
async-异步 sync-同步
asyncio 协程基本格式
#起一个任务 import asyncio #插入asyncio模块 async def demo(): #创建async函数 print('start') await asyncio.sleep(1) #阻塞,阻塞必须写入await之后 且使用asyncio模块自己的方法 print('end') loop = asyncio.get_event_loop() #创建一个第三方事件循环,监测是否IO loop.run_until_complete(demo()) #吧demo任务丢到事件循环中去执行
1
2
3
4
5
6
7
8
9
#起多个任务,且没有返回值
import asyncio
async def demo(): print('start') await asyncio.sleep(1) #阻塞,阻塞必须写入await之后 且使用asyncio模块自己的方法 print('end')
loop = asyncio.get_event_loop() wait_obj=asyncio.wait([demo(),demo(),demo()]) loop.run_until_complete(wait_obj)
```python
#起多个任务,有返回值(了解)
import asyncio
asrnc def demo():
print('start')
await asyncio.sleep(1) #阻塞,阻塞必须写入await之后 且使用asyncio模块自己的方法
print('end')
retunrn 123
loop = asyncio.get-event_loop()
t1 = loop.create_task(demo())
t2 = loop.create_task(demo())
tasks=[t1,t2]
wait_obj=asyncio.wait([t1,t2])
loop.run_until_complete(wait_obj)
for i in easks:
print(tasks.result())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
asyncos是python原生的底层的协程模块
- 爬虫,webserver框架
- 爬虫网络编程的效率和并发效果
await 阻塞必须写在await之后,告诉协程函数这里要切换出去,还能保证一会再切回来
await 必须写在async函数里,async是协程函数
loop 时间循环
- 所有的协程的执行,调度都离不开这个loop
上次更新: 2023/04/16, 18:35:33