Learning Python Coroutine
看了一个视频 OSB 2015 - How Do Python Coroutines Work?,从头开始讲 coroutine 是怎么抽象出来的,感觉好厉害。自己写了一点程序学习了一下。之前写的关于 coroutine 的帖子。
先准备一个 server.py
,可以接受客户端请求。要注意的是要使用 Threading
,或者 fork
的 server,要不服务端执行并不支持并发,需要处理完一个才能处理下一个,这样会发现虽然客户端那边请求是并发的,但是返回结果的时候是顺序的。
1import socketserver
2from time import sleep
3
4HOST = '127.0.0.1'
5PORT = 2045
6
7class MyTCPHandler(socketserver.BaseRequestHandler):
8 def handle(self):
9 data = self.request.recv(1024)
10 sleep(1)
11 self.request.sendall('{} ok'.format(data.decode()).encode())
12
13
14def run():
15 server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
16 server.serve_forever()
17
18if __name__ == '__main__':
19 run()
然后是 client.py
,可以比较下里面 sync_call
和 async_call
的区别。
1import socket
2from time import time
3import asyncio
4
5HOST = '127.0.0.1'
6PORT = 2045
7
8start = time()
9
10def get(path):
11 print('get {}'.format(path))
12 s = socket.socket()
13 s.connect((HOST, PORT))
14
15 s.sendall(path.encode())
16
17 chunk = s.recv(100)
18 print('get {}'.format(chunk.decode()))
19
20def sync_call():
21 get('/bar')
22 get('/foo')
23
24
25async def async_get(path):
26 print('get {}'.format(path))
27 reader, writer = await asyncio.open_connection(HOST, PORT)
28
29 writer.write(path.encode())
30 await writer.drain()
31
32 chunk = await reader.read(100)
33 print('get {}'.format(chunk.decode()))
34
35def async_call():
36 loop = asyncio.get_event_loop()
37
38 t1 = loop.create_task(async_get('/bar'))
39 t2 = loop.create_task(async_get('/foo'))
40
41 loop.run_until_complete(asyncio.gather(t1, t2))
42
43if __name__ == "__main__":
44 #sync_call()
45 async_call()
46 print('total {:.2f} seconds'.format(time() - start))
这里网络请求也需要使用非阻塞的库。创建 task 实际有挺多方法的,这里随便用了一个。