今日主题:前面分享过Python 通过使用回调函数如何实现异步的处理,今天我们将通过一个简单的示例来讲解一下协程是如何实现异步的处理的。
协程的概念 协程,又称微线程,是一种用户态的轻量级线程。协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置,当程序中存在大量不需要CPU的操作时(IO),适用于协程。
协程的优势 协程有极高的执行效率,因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销。
不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程是一个线程执行,所以想要利用多核CPU,最简单的方法是多进程+协程,这样既充分利用多核,又充分发挥协程的高效率。
构成协程的条件
Python 使用协程实现异步
1import threading
2import time
3import datetime
4
5#第一个请求
6def request_1():
7 print("the request 1 is start")
8 data=yield io()#定义一个协程处理
9 print("the response of callback is:",data)
10 print("the request 1 is end")
11
12#第二个请求
13def request_2():
14 print("the request 2 is start")
15 time.sleep(2)#定义耗时2s
16 print("the request 2 is end")
17
18#获取数据请求类的操作,如:从db读取数据,循环耗时,调用其他api等
19def io():
20 def run():
21 print("the run is start")
22 time.sleep(5)#定义耗时5s
23 print("the run is end")
24 conn_db=[x for x in range(10000)] #模拟从db获取数据
25 try:
26 global gen
27 gen.send(conn_db) #线程结束时发送数据给request_1函数里面的data=yeild io(),此时request_1被唤醒继续处理
28 except StopIteration as e:
29 print(e)
30 # 这里是启动一个线程去处理这个io操作,不用阻塞程序的处理,即不影响requst_2的继续处理
31 threading.Thread(target=run,).start()
32
33if __name__ == '__main__':
34 start_time=datetime.datetime.now()
35 global gen
36 gen=request_1() #函数的赋值操作,生成一个生成器
37 next(gen)#调用next函数,预激协程,执行了request_1()函数,如果io被挂起,就直接执行request_2()
38 request_2()
39 end_time=datetime.datetime.now()
40 #这里是在统计总耗时,从打印的结果可以看到是异步处理的。
41 print("the spend of total time is:",(end_time-start_time).seconds)
程序运行后的输出是:
1the request 1 is start
2the run is start
3the request 2 is start
4the request 2 is end
5the spend of total time is: 2
6the run is end
7the response of callback is: [0, 1,...9999]
8the request 1 is end