问:在Py3.5之前yield表现非常好,在Py3.5之后为了将予以变得更加明确,就引入了async和await关键词用于定义原生的协议。

答:async和await原生协程:

async def downloader(url):
return "bobby" async def downloader_url(url):
# do something
html = await downloader(url)
return html if __name__ == '__main__':
coro = downloader_url("http://www.baidu.com")
next(None)
# coro.send(None) # .如果调用send正常
# StopIteration: bobby
# .如果调用next草异常,因此原生协程只能用send
# TypeError: 'NoneType' object is not an iterator
# sys:: RuntimeWarning: coroutine 'downloader_url' was never awaited

  我们发现:原生协程只能用send不能用next。而且发现 原生协程和yield协程差不多,前面加上了async语法,await类似于yield from。Python引入了async和await原生协程是为了我们的语义更加的清晰。如果我们用生成器写出的协程的话,代码非常的凌乱的。因为它又能当生成器又能当协程,显得比较凌乱,将这两种区分开来。因此async里面是不能定义yield的。因此Python加强了我们的区别。因此这两个是一对的。这样我们的协程区分开来。前面说了那么多生成器就是为了加强协程的理解。这样我们在协程里面就用这两个。因此在Python内部依然沿用了生成器的原理,来实现了我们的协程。

  await后跟随的Awaitbale对象。我们可以通过from  collections import Awaitalbe模块。

  其实这个是实现了魔法拿书中的__await__的方法,因此我们还可以使用装饰器的方法来操作,省去asyn,而变换成我们熟悉的生成器的样子。代码如下:

import types

@types.coroutine
def downloader(url):
yield "bobby" async def downloader_url(url):
# do something
html = await downloader(url)
return html if __name__ == '__main__':
coro = downloader_url("http://www.baidu.com")
# next(None)
coro.send(None)

问:生成器是如何变成我们协程的?

答:在开始我么引入过协程的需求,我们的协程是通过单线程调度,协程是我们函数级别的是由我们程序员自己来决定调用的,我们可以写同步代码一样写异步代码。我们的生成器就可以完成我们的协程的这么一个功能。我们现在就可以用协程来模拟我们的需求。

  生成器是可以暂停的函数,实际上生成器是可以有状态的!

  我们看这段代码

import inspect
def gen_func():
yield
return "bobby" if __name__ == '__main__':
gen = gen_func()
print(inspect.getgeneratorstate(gen)) # GEN_CREATED
next(gen)
print(inspect.getgeneratorstate(gen)) # GEN_SUSPENDED
try:
next(gen)
except StopIteration:
pass
print(inspect.getgeneratorstate(gen)) # GEN_CLOSED

  通过inspect中的getgeneratorstate我们来观察生成器的状态,实际上我们在定义我们的生成器的时候,生成器可以接收我们的值。这句话有两个意思:第一是返回值给调用方,第二调用方通过send方式返回值跟gen。现在我们生成器由“生产者”变为“消费者”。

  1.我们用同步的方式编写异步的代码。

  2.在适当的时候暂停函数,并在适当的时候启动函数。

  现在我们模式:事件循环+协程模式

  我们在函数当中的子函数,如果出现异常,会抛给这个函数的主函数,是“向上抛”的过程。这个就很好。协程是一个单线程模式

问:异步IO和IO复用,也就是同步IO和异步IO。

答:我们对前面的东西略微做一个小结:

  异步IO和协程:现在我们还没有把协程来用到我们的编码当中,协程是需要事件循环来实现的。单独使用的话作用不是很明显。

  在最开始的时候我么说到了并发、并行、异步、同步、阻塞、非阻塞。

  在IO多路复用(同步IO)当中的select poll epoll,使我们使用的最多的技术。回调+事件循环的方式。这种编程模式和同步IO的编程模式差别很大。

  因此这两种模式:回调+事件循环(IO多路复用)、协程+事件循环(异步IO)

  上面的编码是非常痛苦的:回调之痛。

  我们引入了生成器和协程,协程并不会别上面的方式高,协程主要解决的问题是回调之痛的问题和编码习惯的问题。

  我们可以将生成器编程我们的协程了。

  最后引入了async和await来区别生成器和协程,不容易混乱,进行区分。我们可以用Cororoutine装饰器的方式,就不要用了。

  所以建议使用async和await的方式。

问:async IO并发编程:

答:该模块是在Python3.4后引入的模块,这是Python编程中最难的部分。该模块也是Python最具野心的模块。分几个部分开始讲解:

  1. 事件循环:

  我们可以把async IO看做一个模块也可看做一个框架,它完成了整套异步编程中最核心的内容。它包含各种特定系统实现的模块化事件循环,传输和协议抽象;对TCP,UDP,SSL,子进程,延时调用以及其他的具体支持;模仿futures模块但适用于事件循环使用Future类;基于yield from的协议和任务,可以让你用顺序的方式编写并发代码;必须使用一个将产生阻塞IO的调用时,有接口可以把这个事件转移到线程池。可以将多进程和多线程协调进来。

  协程编码模式都逃离不掉三个要素:事件循环+调用(驱动生成器)+epoll(IO多路复用)

  asyncio 是Python用于解决异步IO编程的一整套解决方案。

  tornado、gevent、twisted(scrapy,django channels)

  tornado:实现了web服务器,djago+flask是Python最传统要搭配(uwsgi,gunicorn+nginx),tornado可以直接部署,nginx+tornado

  使用asyncio

import asyncio # 可以当做协程池来理解比较容易

import time

async def get_html(url):
print("start get url")
# time.sleep() # 阻塞式的IO不能写在里面
await asyncio.sleep() # 不能使用import time,必须要加await
print("end get url") if __name__ == '__main__':
start_time = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(get_html("htttp://www.baidu.com"))
print(time.time() - start_time) # start get url
# end get url
# 2.0150375366210938

  get_event_loop市价循环

  run_until_complete去执行

  这里不能用time.sleep这是阻塞式的方法。因此会单独的一个一个执行非常慢,所以要使用asynic中的sleep

import asyncio # 可以当做协程池来理解比较容易

import time

async def get_html(url):
print("start get url")
# time.sleep() # 阻塞式的IO不能写在里面
await asyncio.sleep() # 不能使用import time,必须要加await
print("end get url") if __name__ == '__main__':
start_time = time.time()
loop = asyncio.get_event_loop()
tasks = [get_html("htttp://www.baidu.com") for i in range()]
loop.run_until_complete(asyncio.wait(tasks))
print(time.time() - start_time) # start get url
# end get url
# 2.0150375366210938
# time编程顺序执行。asyncio.sleep()可以立即执行。只要一个地方阻塞了其他方面都实现不了。

  我们发现更改后就会阻塞。

import asyncio # 可以当做协程池来理解比较容易

import time

async def get_html(url):
print("start get url")
# time.sleep() # 阻塞式的IO不能写在里面
await asyncio.sleep() # 不能使用import time,必须要加await
return "bobby"
if __name__ == '__main__':
start_time = time.time()
loop = asyncio.get_event_loop()
# get_future = asyncio.ensure_future(get_html("htttp://www.baidu.com"))
# loop.create_task()
# tasks = [get_html("htttp://www.baidu.com") for i in range()]
task = loop.create_task(get_html("htttp://www.baidu.com"))
loop.run_until_complete(task)
print(time.time() - start_time)
print(task.result()) # 获取协程的返回值

  我们用协程调用线程池:ensure_funture

  使用方法还有create_task这两种都是比较好理解的。

import asyncio # 可以当做协程池来理解比较容易

import time
from functools import partial async def get_html(url):
print("start get url")
# time.sleep() # 阻塞式的IO不能写在里面
await asyncio.sleep() # 不能使用import time,必须要加await
return "bobby" def callback(url,future):
print("send email to bobby") if __name__ == '__main__':
start_time = time.time()
loop = asyncio.get_event_loop()
# get_future = asyncio.ensure_future(get_html("htttp://www.baidu.com"))
# loop.create_task()
# tasks = [get_html("htttp://www.baidu.com") for i in range()]
task = loop.create_task(get_html("htttp://www.baidu.com"))
# task.add_done_callback(callback)
task.add_done_callback(partial(callback,"htttp://www.baidu.com"))
loop.run_until_complete(task)
print(time.time() - start_time)
print(task.result()) # 获取协程的返回值

  我们也可以使用回调,在task中的重写add_done_callback方法。

import asyncio # 可以当做协程池来理解比较容易

import time

async def get_html(url):
print("start get url")
# time.sleep() # 阻塞式的IO不能写在里面
await asyncio.sleep() # 不能使用import time,必须要加await
print("end get url") if __name__ == '__main__':
start_time = time.time()
loop = asyncio.get_event_loop()
tasks = [get_html("htttp://www.baidu.com") for i in range()]
# loop.run_until_complete(asyncio.wait(tasks))
loop.run_until_complete(asyncio.gather(*tasks))
print(time.time() - start_time) # wait 和 gather 的区别
# gather更加高层,可以将我们task分组
group1 = [get_html("htttp://www.baidu1.com") for i in range()]
group2 = [get_html("htttp://www.baidu2.com") for i in range()]
loop.run_until_complete(asyncio.gather(*group1,*group2)) group1 = asyncio.gather(*group1)
group2 = asyncio.gather(*group2) group2.cancel()

  我们尽量使用gather方法,注意他是可以将我们task进行分组,后面要加上*参数的形式。

  2. task取消、嵌套、字写成调用原理

# import asyncio
#
# loop = asyncio.get_event_loop()
# loop.run_forever()
# loop.run_until_complete()
# .loop会被放到future中。
# .取消future(task)
import asyncio
import time async def get_html(sleep_times):
print("waiting")
await asyncio.sleep(sleep_times)
print("done after {}s".format(sleep_times)) if __name__ == '__main__':
task1 = get_html()
task2 = get_html()
task3 = get_html()
tasks = [task1,task2,task3] loop = asyncio.get_event_loop() try:
loop.run_until_complete(asyncio.wait(tasks))
except KeyboardInterrupt as e:
all_task = asyncio.Task.all_tasks()
for task in all_task:
print("cancel task")
task.cancel()
loop.stop()
loop.run_forever()
finally:
loop.close()

  3. call_soon() 即刻执行,call_later(),call_at()

  4.ThreadPoolExector   + asyncio

  使用多线程:在协程中继承阻塞io

  生成器 = ThreadPoolExecutor

  run_in+executor(生成器,函数,参数)

11111

最新文章

  1. H5坦克大战之【建造敌人的坦克】
  2. 应用程序Cache对象到高性能Memcached学习之路
  3. Linux(Red Hat)-中安装Vmware Tools
  4. 数据结构——B树、B+树
  5. Android Studio NDK 学习之接受Java传入的Int数组
  6. Android sdk manager不能更新下载缓慢的解决方法
  7. html textarea 获取换行
  8. (*medium)LeetCode 211.Add and Search Word - Data structure design
  9. Microsoft.Jet.Oledb.4.0 提供者並未登錄於本機電腦上
  10. [分享]WPF 虚拟键盘
  11. 在Word中直接用快捷键查找选中文本
  12. Android 手势&触摸事件 MotionEvent
  13. c# 服务程序重启自身
  14. ajax实现用户名校验的传统和jquery的$.post方式
  15. Centos7】hostnamectl 设置主机名
  16. python 三目运算符
  17. python学习笔记(五)
  18. Web缓存机制
  19. Kubernetes之容器
  20. asp.net core json返回的时间格式出现T 如何解决

热门文章

  1. vscode dart 插件 关闭自动注释
  2. 原型与继承与class
  3. 033、Java中使用简化运算符
  4. CharacterEncodingFilter详解及源码解析
  5. NO3 cat-xargs-cp-mv-rm-find命令
  6. M3U8地址在谷歌浏览器中播放
  7. 微信小程序如何刷新当前界面
  8. Git详细命令
  9. Codeforces 176B 经典DP
  10. JS给对象添加新字段