Python-asyncio

1、asyncio 

  3.4版本加入标准库

  asyncio 底层基于selectors 实现,看似库,其实就是一个框架,包含异步IO,事件循环,协程,任务等待等内容。   

2、问题引出

def a():
    for x in range(3):
        print(x)

def b():
    for x in 'abc':
        print(x)
a()
b()

# 运行结果
0
1
2
a
b
c

 

这是一个串行的程序。

def a():
    for x in range(3):
        print(x)
        yield

def b():
    for x in 'abc':
        print(x)
        yield

x = a()
y = b()
for i in range(3):
    next(x)
    next(y)

 

3、事件循环:

  事件循环是asyncio 提供的核心运行机制

  

4、协程

  • 协程不是进程,也不是线程,它是用户空间调度的完成并发处理的方式
  • 进程,线程由操作系统完成调度,而协程是线程内完成调度。它不需要更多的线程,自然也没有多线程切换带来的开销
  • 协程是非抢占式调度,只有一个协程主动让出控制权,另一个协程才会被调度
  • 协程不需要使用锁机制,因为在同一个线程中执行。
  • 多CPU下,可以使用多进程和协程配合,既能进程并发,又能发挥协程在单线程中的 优势
  • Python中协程是基于生成器的。

5、协程的使用

  3.4引入asyncio ,使用装饰器

  asyncio.sleep(0.001):也是一个coroutine,是一个生成器函数,yield值
 1 import asyncio
 2 
 3 @asyncio.coroutine
 4 def sleep(x): #  协程函数
 5     for i in range(3):
 6         print('sleep {}'.format(i))
 7         yield from asyncio.sleep(x)
 8 
 9 loop = asyncio.get_event_loop()
10 loop.run_until_complete(sleep(3)) # 将sleep(3) 封装成Task对象执行
11 loop.close()
12 print('===================')

    结果:每一秒打印一个,最终打印 ========

1 sleep 0
2 sleep 1
3 sleep 2
4 ===================

 

  将生成器函数,转换为协程函数,就可以在时间循环中执行了。

  测试:

 1 import asyncio
 2 
 3 @asyncio.coroutine
 4 def sleep(x):
 5     for i in range(3):
 6         print('sleeP {}'.format(i))
 7         yield from asyncio.sleep(x)
 8 
 9 loop = asyncio.get_event_loop()
10 
11 #自己封装 task 对象
12 task = loop.create_task(sleep(3))
13 print(1, task)
14 loop.run_until_complete(task)
15 print(2, task)
16 loop.close()
17 print('======== end =======')

  结果:

1 1 <Task pending coro=<sleep() running at E:/code_pycharm/tt10.py:23>>
2 sleeP 0
3 sleeP 1
4 sleeP 2
5 2 <Task finished coro=<sleep() done, defined at E:/code_pycharm/tt10.py:23> result=None>
6 ======== end =======

 

  测试:添加回调函数,知道运行完,返回结果(异步非阻塞)

 1 import asyncio
 2 
 3 @asyncio.coroutine
 4 def sleep(x):
 5     for i in range(3):
 6         print('sleeP {}'.format(i))
 7         yield from asyncio.sleep(0.001)
 8     # 给一个result
 9     return 2000
10 
11 def cb(future): # 回调函数
12     print(4, future,'===')
13     print(5, future.result())
14 
15 loop = asyncio.get_event_loop()
16 
17 #自己封装 task 对象
18 task = loop.create_task(sleep(3))
19 task.add_done_callback(cb)# 注册了一个回调函数
20 print(1, task)
21 loop.run_until_complete(task)
22 print(2, task)
23 print(3, task.result()) # 获取结果
24 loop.close()
25 print('======== end =======')

 

  结果:打印2 之前,先执行了回调函数,且得到最终结果之前,一直在运行

1 1 <Task pending coro=<sleep() running at E:/code_pycharm/tt10.py:42> cb=[cb() at E:/code_pycharm/tt10.py:50]>
2 sleeP 0
3 sleeP 1
4 sleeP 2
5 4 <Task finished coro=<sleep() done, defined at E:/code_pycharm/tt10.py:42> result=2000> ===
6 5 2000
7 2 <Task finished coro=<sleep() done, defined at E:/code_pycharm/tt10.py:42> result=2000>
8 3 2000
9 ======== end =======

 

 

  测试:多任务:

 1 import asyncio
 2 
 3 @asyncio.coroutine
 4 def sleep(x):
 5     for i in range(3):
 6         print('sleeP {}'.format(i))
 7         yield from asyncio.sleep(0.001)
 8     # 给一个result
 9     return 2000
10 
11 @asyncio.coroutine
12 def b():
13     for x in 'abc':
14         print(x)
15         yield from asyncio.sleep(0.001)
16 
17 
18 def cb(future): # 回调函数
19     print(4, future,'===')
20     print(5, future.result())
21 
22 loop = asyncio.get_event_loop()
23 
24 #自己封装 task 对象
25 task = loop.create_task(sleep(3))
26 task.add_done_callback(cb)# 注册了一个回调函数
27 print(1, task)
28 # 固定套路,多任务
29 tasks = [task, b()]
30 ret = loop.run_until_complete(asyncio.wait(tasks))
31 
32 print(2, task)
33 print(3, task.result()) # 获取结果
34 print(6, ret)
35 loop.close()
36 print('======== end =======')

  结果:

 1 1 <Task pending coro=<sleep() running at E:/code_pycharm/tt10.py:42> cb=[cb() at E:/code_pycharm/tt10.py:57]>
 2 sleeP 0
 3 a
 4 sleeP 1
 5 b
 6 sleeP 2
 7 c
 8 4 <Task finished coro=<sleep() done, defined at E:/code_pycharm/tt10.py:42> result=2000> ===
 9 5 2000
10 2 <Task finished coro=<sleep() done, defined at E:/code_pycharm/tt10.py:42> result=2000>
11 3 2000
12 6 ({<Task finished coro=<sleep() done, defined at E:/code_pycharm/tt10.py:42> result=2000>, <Task finished coro=<b() done, defined at E:/code_pycharm/tt10.py:50> result=None>}, set())
13 ======== end =======

 

  可以看出,返回一个元组,把之前的任务都会放在里边

    所以获取每个任务的result的方式:

      1、将任务封装为task,通过回调函数,或者,直接调用result()

      2、通过任务列表返回的结果,遍历获取        

print(6, ret[0])
for i in ret[0]:
    print(i.result())

 

  3.5版本之后,Python提供关键字async,await,在语言上原生支持协程

 1 import asyncio
 2 
 3 async def sleep(x):
 4     for i in range(3):
 5         print('sleeP {}'.format(i))
 6         await asyncio.sleep(0.001)
 7     # 给一个result
 8     return 2000
 9 
10 async def b():
11     for x in 'abc':
12         print(x)
13         await asyncio.sleep(0.001)
14 
15 
16 def cb(future): # 回调函数
17     print(4, future,'===')
18     print(5, future.result())
19 
20 loop = asyncio.get_event_loop()
21 
22 #自己封装 task 对象
23 task = loop.create_task(sleep(3))
24 task.add_done_callback(cb)# 注册了一个回调函数
25 print(1, task)
26 
27 tasks = [task, b()]
28 ret = loop.run_until_complete(asyncio.wait(tasks))
29 
30 print(2, task)
31 print(3, task.result()) # 获取结果
32 print(6, ret[0])
33 for i in ret[0]:
34     print(i.result())
35 loop.close()
36 print('======== end =======')

 

  async def 用来定义协程函数,iscoroutinefunction() 返回True,协程函数中可以不包含await,async关键字,但不能使用yield 关键字

  如同生成器函数调用返生成器对象一样,协程函数调用 也会返回一个对象称为协程对象,iscoroutine()返回True。

  await语句之后是awaitable对象,可以是协程或者实现了__await__()方法的对象,await会暂停当前协程执行,使用loop调度其他协程。

 

  tcp  ECho server:

 1 import asyncio
 2 
 3 async def handle(reader:asyncio.StreamReader, writer:asyncio.StreamWriter):
 4     while True:
 5         data = await reader.read(1024)
 6         print(dir(reader))
 7         print(dir(writer))
 8         client = writer.get_extra_info('peername')
 9         message = '{} your msg {}'.format(client, data.decode()).encode()
10         writer.write(message)
11         await writer.drain() # 注意不是flush 方法
12 loop = asyncio.get_event_loop()
13 ip = '127.0.0.1'
14 port = 9999
15 crt = asyncio.start_server(handle, ip, port, loop=loop)
16 
17 server = loop.run_until_complete(crt)
18 print(server)
19 try:
20     print('=========')
21     loop.run_forever()
22 except KeyboardInterrupt:
23     pass
24 finally:
25     server.close()
26     loop.run_until_complete(server.wait_closed())
27     loop.close()
View Code

 

 

6、aiohttp库(异步的)

pip install aiohttp

文档:https://aiohttp.readthedocs.io/en/stable/

http server

http client

 

posted @ 2018-11-06 21:23  JerryZao  阅读(275)  评论(0编辑  收藏  举报