[Python 多线程] asyncio (十六)

asyncio

该模块是3.4版本加入的新功能。

先来看一个例子:

def a():
    for x in range(3):
        print(‘a.x‘, x)

def b():
    for x in ‘abc‘:
        print(‘b.x‘, x)

a()
b()

#运行结果:
a.x 0
a.x 1
a.x 2
b.x a
b.x b
b.x c

  这个例子是一个典型的串行程序,两个函数调用是在主线程中顺序执行。

有以下几种方法可以让这段程序改为并行:

1. 生成器

2. 多线程

3. 多进程

4. 协程

1)生成器方法:

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

def b():
    for x in ‘abc‘:
        yield x

m = a()
n = b()

for _ in range(3):
    print(next(m))
    print(next(n))

#运行结果:
0
a
1
b
2
c

  使用生成器来实现交替执行。这两个函数都有机会执行,这样的调度不是操作系统的进程、线程完成的,而是用户自己设计的。

2)多线程方法:

import threading,time

def a():
    for x in range(3):
        time.sleep(0.0001)
        print(‘a.x‘,x)

def b():
    for x in ‘abc‘:
        time.sleep(0.0001)
        print(‘b.x‘,x)

threading.Thread(target=a).start()
threading.Thread(target=b).start()

#运行结果:
a.x 0
b.x a
a.x 1
b.x b
a.x 2
b.x c

  主要使用sleep函数强制切换来实现伪并行。

3)多进程方式:

import multiprocessing

def a():
    for x in range(3):
        print(‘a.x‘,x)

def b():
    for x in ‘abc‘:
        print(‘b.x‘,x)

if __name__ == ‘__main__‘:
    multiprocessing.Process(target=a).start()
    multiprocessing.Process(target=b).start()

#运行结果:
a.x 0
a.x 1
a.x 2
b.x a
b.x b
b.x c

  多进程方式才是真正的并行。

4)协程方法:

协程,需要使用到 asyncio 标准库,是Python3.4版本加入的新功能,底层基于selectors实现,包括异步IO、事件循环、协程等内容。

事件循环:

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

程序开启一个无限的循环,使用者会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。

4.1 事件循环基类

asyncio.BaseEventLoop  这个类是一个实现细节,它是asyncio.AbstractEventLoop的子类,不可以直接使用
asyncio.AbstractEventLoop  事件循环的抽象基类,这个类是是线程不安全的

4.2 运行事件循环

asyncio.get_event_loop()  返回一个事件循环对象,是asyncio.BaseEventLoop的实例
asyncio.AbstractEventLoop.stop()  停止运行事件循环
asyncio.AbstractEventLoop.run_forever()  一直运行,直到调用stop()
asyncio.AbstractEventLoop.run_until_complete(future)  运行直到future对象运行完成,返回结果
asyncio.AbstractEventLoop.close()  关闭事件循环
asyncio.AbstractEventLoop.is_running()  返回事件循环的运行状态
asyncio.AbstractEventLoop.is_closed()  如果事件循环已关闭,返回True

4.3 协程

协程不是进程、也不是线程,它是用户空间调度完成并发处理的方式。(同一线程内交替执行其实也是伪并发)

并发指的是在一段时间内做了多少、并行指的是同一时刻有多少同时执行。

进程、线程由操作系统完成调度,而协程是线程内完成调度。它不需要更多的线程,也就没有多线程切换带来的开销。

协程是非抢占式调度,只有一个协程主动让出控制权,另一个协程才会被调度。

协程也不需要锁机制,因为是在同一线程中执行。

多CPU下,可以使用多线程和协程配合,既能进程并发又能发挥协程在单线程中的优势。

Python中协程是基于生成器的。

4.4 协程的使用

4.4.1 Python3.4中使用@asyncio.coroutine 、 yield from

#asyncio Python3.4

import asyncio

@asyncio.coroutine
def foo(x): #生成器函数上面加了协程装饰器之后就转化成协程函数
	for i in range(3):
		print(‘foo {}‘.format(i))
		yield from asyncio.sleep(x) #调用另一个生成器对象

loop = asyncio.get_event_loop() #获得一个时间循环
loop.run_until_complete(foo(1)) #传入一个生成器对象的调用
loop.close()

#运行结果:
foo 0
foo 1
foo 2
[Finished in 3.3s]

  此例子在一个生成器函数加了协程装饰器之后,该生成器函数就转化成了协程函数。

4.4.2 Python3.5中使用关键字 async def 、 await ,在语法上原生支持协程

#asyncio Python3.5

import asyncio

async def foo(x):  #异步定义,协程定义
	for i in range(3):
		print(‘foo {}‘.format(i))
		await asyncio.sleep(x) #不可以出现yield,使用await替换

print(asyncio.iscoroutinefunction(foo))
loop = asyncio.get_event_loop()
loop.run_until_complete(foo(1)) #传入一个协程对象的调用
loop.close()

#运行结果:
True
foo 0
foo 1
foo 2
[Finished in 3.3s]

  async def 用来定义协程函数,iscoroutinefunction(func)判断func函数是否是一个协程函数。协程函数中可以不包含await、async关键字,但不能使用yield关键字。

其它语法:async with,支持上下文的协程

4.4.3 coroutine asyncio.wait(futures, *, loop=None, timeout=None, return_when=ALL_COMPLETED)

等待futures序列中的协程对象执行完成,futures序列不可以为空。

timeout可以用于控制返回前等待的最大秒数,秒数可以是int或浮点数,如果未指定timeout,则无限制。

#wait多个协程对象
import asyncio

@asyncio.coroutine
def a():
	for i in range(3):
		print(‘a.x‘,i)
		yield

@asyncio.coroutine
def b():
	for i in range(3):
		print(‘b.x‘,i)
		yield

loop = asyncio.get_event_loop()
tasks = [a(),b()]
loop.run_until_complete(asyncio.wait(tasks)) #传入一个协程对象序列

loop.close()

#运行结果:
b.x 0
a.x 0
b.x 1
a.x 1
b.x 2
a.x 2
[Finished in 0.3s]

  

总结:

传统的多线程、多进程都是系统完成调度,而协程是在进程中的线程内由用户空间调度完成并发处理,主要依靠生成器来实现交替调度。

Python3.4中使用@asyncio.coroutine、yield from调用另一个生成器对象

Python3.5中使用关键字 async def 和 await,且不可以出现yield关键字。

原文地址:https://www.cnblogs.com/i-honey/p/8110824.html

时间: 2024-08-30 13:09:43

[Python 多线程] asyncio (十六)的相关文章

秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据

版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 本文配套程序下载地址为:http://download.csdn.net/detail/morewindows/5136035 转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8646902 欢迎关注微博:http://weibo.com/MoreWindows 在<秒杀多线程系列>的前十五篇中介绍多线程的相关概念,多线程同步互斥问题<秒杀多

Python进阶(三十六)-Web框架Django项目搭建全过程

Python进阶(三十六)-Web框架Django项目搭建全过程 ??IDE说明: Win7系统 Python:3.5 Django:1.10 Pymysql:0.7.10 Mysql:5.5 ??Django 是由 Python 开发的一个免费的开源网站框架,可以用于快速搭建高性能,优雅的网站! Django 特点 强大的数据库功能 用python的类继承,几行代码就可以拥有一个丰富,动态的数据库操作接口(API),如果需要你也能执行SQL语句. 自带的强大的后台功能 几行简单的代码就让你的网

“全栈2019”Java多线程第二十六章:同步方法生产者与消费者线程

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第二十六章:同步方法生产者与消费者线程 下一章 "全栈2019"Java多线程第二十七章:Lock获取lock/释放unlock锁 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorha

Python 学习 第十六篇:networkx

networkx是Python的一个包,用于构建和操作复杂的图结构,提供分析图的算法.图是由顶点.边和可选的属性构成的数据结构,顶点表示数据,边是由两个顶点唯一确定的,表示两个顶点之间的关系.顶点和边也可以拥有更多的属性,以存储更多的信息. 对于networkx创建的无向图,允许一条边的两个顶点是相同的,即允许出现自循环,但是不允许两个顶点之间存在多条边,即出现平行边. 边和顶点都可以有自定义的属性,属性称作边和顶点的数据,每一个属性都是一个Key:Value对. 一,创建图 在创建图之前,需要

python学习笔记十六 django深入学习一

django 请求流程图 django 路由系统 在django中我们可以通过定义urls,让不同的url路由到不同的处理函数 from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), #精确匹配 url(r'^articles/([0-9]{4})/$', views.year_archive), #动态路由 url(r'^articles/([0-9]{4})/([0-9]{2

跟着刚哥梳理java知识点——多线程(十六)

创建多线程第一种方式:① 继承:继承Thread.② 重写:重写Thread类的run()方法③ 创建:创建一个子类的对象④ 调用:调用线程的start()方法,启动此线程,调用run()方法 1 class Work extends Thread{ //① 继承 2 @Override 3 //② 重写 4 public void run() { 5 for (int i = 1 ;i < 5; i++) { 6 System.out.println(Thread.currentThread(

笨办法学Python(二十六)

习题 26: 恭喜你,现在可以考试了! 你已经差不多完成这本书的前半部分了,不过后半部分才是更有趣的.你将学到逻辑,并通过条件判断实现有用的功能. 在你继续学习之前,你有一道试题要做.这道试题很难,因为它需要你修正别人写的代码.当你成为程序员以后,你将需要经常面对别的程序员的代码,也许还有他们的傲慢态度,他们会经常说自己的代码是完美的. 这样的程序员是自以为是不在乎别人的蠢货.优秀的科学家会对他们自己的工作持怀疑态度,同样,优秀的程序员也会认为自己的代码总有出错的可能,他们会先假设是自己的代码有

python 全栈 python基础 (十六)面向对象编程的 继承 多态与多态性 封装

一.继承顺序: 多继承情况下,有两种方式:深度优先和广度优先 1.py3/py2 新式类的继承:在查找属性时遵循:广度优先 继承顺序是多条分支,按照从左往右的顺序,进行一步一步查找,一个分支走完会走另一个分支(若多条分支汇总一个头,除最后一条分支能走到头,其他的都走到次之位置停止,进行下一条分支的查找),直到查找到头为止. 可以利用 类名.__mro__ 的方法查看类之间的继承关系(经典类没有这种方法) 1 class B(object): 2 def func(self): 3 print('

[Python笔记]第十六篇:web框架之Tornado

Tornado是一个基于python的web框架,xxxxx 安装 python -m pip install tornado 第一个Tornado程序 安装完毕我们就可以新建一个app.py文件,放入下面的代码直接运行就可以了,然后在浏览器访问127.0.0.1:8888 import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.writ