问:在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

Python说文解字_Python之多任务_05的更多相关文章

  1. Python说文解字_Python之多任务_01

    Python 之 多任务: Python之多任务是现在多任务编程运用Python语言为载体的一种体现.其中涵盖:进程.线程.并发等方面的内容,以及包括近些年在大数据运算.人工智能领域运用强大的GPU运 ...

  2. Python说文解字_Python之多任务_03

    问:线程学完了,现在我们开始学习进程了吧? 答:是的.前面说到线程就是我们的手,我们现在可以学习一下我们的“胳膊”了. 我们有了多线程,为什么还要学习多进程呢?这是因为在Python当中有一把GIL锁 ...

  3. Python说文解字_Python之多任务_02

    第三部分:Semaphore控制进入数量的锁 有时候可能需要运行多个工作线程同时访问一个资源,但要限制总数.例如,连接池支持同时连接,但是数目可能是固定的,或者一个网络应用可能支持固定数据的并发下载. ...

  4. Python说文解字_Python之多任务_04

    问:并发.并行.同步.异步.阻塞.非阻塞 答: 并发.并行: 并发是指一个时间段内(不是指的时间点),有几个程序在同一个CPU上运行,但是任意时刻只有一个程序在CPU上运行.对人类的时钟来说1秒钟能干 ...

  5. Python说文解字_详解元类

    1.深入理解一切接对象: 1.1 什么是类和对象? 首先明白元类之前要明白什么叫做类.类是面向对象object oriented programming的重要概念.在面向对象中类和对象是最基本的两个概 ...

  6. Python说文解字_杂谈05

    1. isinstance和type: is和==符号,is指的是内存地址,是不是一个对象,ID知否相同 集成链 class A: pass class B(A): pass b = B() prin ...

  7. Python说文解字_杂谈09

    1. 元类编程代码分析: import numbers class Field: pass class IntField(Field): # 数据描述符: # 初始化 def __init__(sel ...

  8. Python说文解字_杂谈08

    1. Python变量到底是什么? Python和Java中的变量本质不一样,python的变量实质是一个指针 int str,便利贴 a = 1 # 1. a贴在1上面 # 2. 它的过程是先生成对 ...

  9. Python说文解字_杂谈07

    1. 深入dict from collections.abc import Mapping,MutableMapping # dict 属于mapping类型 a = {} print(isinsta ...

随机推荐

  1. 014.CI4框架CodeIgniter数据库操作之:查询数据库,并让数据以对象的方式返回查询结果

    01. 我们在CI4框架中的Model文件夹新建一个User_model.php的文件,使用的是getResultArray,表示并让数据以数组的方式返回查询结果,代码如下: <?php nam ...

  2. 0101-ioc

    背景 ioc是spring的基础,即控制反转.springboot基于注解使用ioc. ioc spring称所有被管理的对象为bean, spring ioc主要通过描述的方式完成3类bean的管理 ...

  3. MS SQLSERVER 自增ID列竟然会重复

    MS SQLSERVER 2008 R2 datacenter edition 自增的ID列,设为了主键. 从没遇到过的情况.

  4. MyBatis 逆向工程(MyBatis 自动生成接口以及xml)的使用

    刚学MyBatis逆向工程(还以为要反汇编呢.....) MyBatis逆向工程 个人理解就是链接数据库自动生成相关的增删改查相关的类 以及xml文件 (其中有一些不足 应该就是多表链接的问题需要自己 ...

  5. ACM-寻宝

    题目描述:寻宝 有这么一块神奇的矩形土地,为什么神奇呢?因为上面藏有很多的宝藏.该土地由N*M个小正方形土地格子组成,每个小正方形土地格子上,如果标有“E”,则表示该格可以通过:如果标有“X”,则表示 ...

  6. node - 获取 token

     String(req.headers.authorization || '').split(' ').pop() 

  7. 如何通过 Python 和 OpenCV 实现目标数量监控?

    今天我们将利用python+OpenCV实现对视频中物体数量的监控,达到视频监控的效果,比如洗煤厂的监控水龙头的水柱颜色,当水柱为黑色的超过了一半,那么将说明过滤网发生了故障.当然不仅如此,我们看的是 ...

  8. linux之 文本编辑 的基础知识点

    第一步 打开终端 创建文件命令 touch 文件名.后缀名 打开文件命令 vi 文件名.后缀名 (此时进去txt文件之后为一般模式,你无法对文件进行增删改) 之后按 i    或 a    或o  都 ...

  9. pycharm 设置项目的编译器

    设置编译器(interpreter) File---Setting--在搜索框输入(interpreter)

  10. (21)Laplance

    这个算法还是用来进行边缘检测的 =============================== #include <opencv2/opencv.hpp> #include <ios ...