asyncio:异步I/O、事件循环和并发工具(持续跟新中)

流畅的Python书中的协程部分版本太低,而且讲的比较少,这次根据Python3标准库书中实例来学习记录asyncio的使用。

asyncio模块提供了使用次饿成构建并发应用的工具。threading模块通过应用线程并发,mutilprocessing使用系统进程实现并发,asyncio则使用一个单线程单进程的方法来实现并发,应用的各个部分会彼此合作,在最优的时刻显式地切换任务。

asyncio提供的框架以一个事件循环(event loop)为中心,这是一个首类对象,负责高效地处理I/O事件、系统事件、和应用的上下文切换。

就现在本人的了解,一般的io应用中,还是以多线程使用为主,自己在写协程并发的时候,多个协程之间,无法有效的设置条件交出控制权。

唯一能应用的包,就一个aiohttp,如果我想用另外的包实现协程,基本无法做到,然而协程asyncio包就像流畅的Python书中所说,大部分在讲概念和API,

也只能希望后面能有更加丰富的包来配合协程,或者等我哪一天成为高手,写出能配合协程的包。

2、利用协程合作完成多任务

import asyncio

async def coroutine():
    print(‘in coroutine‘)

# 定义事件循环
event_loop = asyncio.get_event_loop()

try:
    print(‘starting coroutine‘)
    coro = coroutine()
    print(‘entering event loop‘)
    # 运行协程
    event_loop.run_until_complete(coro)
finally:
    print(‘closing event loop‘)
    event_loop.close()
/usr/local/bin/python3.7 /Users/shijianzhong/study/t_asyncio/asyncio_coroutine.py
starting coroutine
entering event loop
in coroutine
closing event loop

Process finished with exit code 0

先通过get_event_loop创建一个默认的事件循环,run_until_complete方法驱动里面的协程,最后关闭事件循环。

从协程返回值

import asyncio

# 有返回值
async def coroutine():
    print(‘in coroutine‘)
    return ‘result‘

# 定义事件循环
event_loop = asyncio.get_event_loop()

try:
    print(‘starting coroutine‘)
    coro = coroutine()
    print(‘entering event loop‘)
    # 运行协程,获取值
    return_value = event_loop.run_until_complete(coro)
    print(f‘it returned: {return_value!r}‘)
finally:
    print(‘closing event loop‘)
    event_loop.close()
/usr/local/bin/python3.7 /Users/shijianzhong/study/t_asyncio/asyncio_coroutine_return.py
starting coroutine
entering event loop
in coroutine
it returned: ‘result‘
closing event loop

Process finished with exit code 0

串链协程

import asyncio

async def outer():
    print(‘in outer‘)
    print(‘waiting for result1‘)
    # 接收phase1()协程产生的值
    result1 = await phase1()
    print(‘waiting for result2‘)
    # 接收phase2()协程产生的值
    result2 = await phase2(result1)
    return result1, result2

async def phase1():
    print(‘in parse1‘)
    return ‘result1‘

async def phase2(arg):
    print(‘in phase2‘)
    return ‘result2 derived from {}‘.format(arg)

event_loop = asyncio.get_event_loop()
try:
    return_value = event_loop.run_until_complete(outer())
    print(f‘return_value:{return_value!r}‘)
finally:
    event_loop.close()
/usr/local/bin/python3.7 /Users/shijianzhong/study/t_asyncio/asyncio_coroutine_chain.py
in outer
waiting for result1
in parse1
waiting for result2
in phase2
return_value:(‘result1‘, ‘result2 derived from result1‘)

Process finished with exit code 0

生成器而不是协程

Python3.5开始

async 代替了@asyncio.coroutine

await 代替了 yield from

本人觉得await 还是yield from更加直观。

3、调度常规函数调用

这个使用的话,需要把事件循环传递放入协程中,协程中通过事件循环的方法去激活需要调用的函数。

在传入事件循环的协程里面必须设置asyncio.seleep,要不然协程不会让出控制权,事件循环根本无法激活调用函数。

import asyncio
from functools import partial

def callback(arg, *, kwarg=‘default‘):
    print(f‘callback invoked with {arg} and {kwarg}‘)

async def main(loop):
    print(‘registering callbacks‘)
    # 调用函数,只能传入一个参数,多参数传入调用partial
    loop.call_soon(callback, 1)
    # 通过partial传入关键字参数
    wrapped = partial(callback, kwarg=‘not default‘)
    loop.call_soon(wrapped, 2)

    await asyncio.sleep(.1)

event_loop = asyncio.get_event_loop()
try:
    print(‘entering event loop‘)
    event_loop.run_until_complete(main(event_loop))
finally:
    event_loop.close()
/usr/local/bin/python3.7 /Users/shijianzhong/study/t_asyncio/asyncio_call_soon.py
entering event loop
registering callbacks
callback invoked with 1 and default
callback invoked with 2 and not default

Process finished with exit code 0

用Delay调度回调

call_soon是直接调用,call_later()第一个参数可以传入延后的事件,单位为秒,第二个参数为function

在传入事件循环的协程里面必须设置asyncio.seleep,且大于最迟的调用函数时间,要不然协程不会让出控制权,事件循环根本无法激活调用函数。

import asyncio
from functools import partial

def callback(arg):
    print(f‘callback invoked {arg}‘)

async def main(loop):
    print(‘registering callbacks‘)
    # 调用函数,第一个参数传入时间
    loop.call_later(0.2, callback, 1)
    loop.call_later(0.1, callback, 2)
    # 这个很重要
    await asyncio.sleep(.21)

event_loop = asyncio.get_event_loop()
try:
    print(‘entering event loop‘)
    event_loop.run_until_complete(main(event_loop))
finally:
    print(‘closing event loop‘)
    event_loop.close()
/usr/local/bin/python3.7 /Users/shijianzhong/study/t_asyncio/asyncio_call_later.py
entering event loop
registering callbacks
callback invoked 2
callback invoked 1
closing event loop

Process finished with exit code 0

在指定事件内调度一个回调

实现这个目的的循环依赖的是一个所谓的单调时钟,用loop.time()生成,激活用call_at

import asyncio
import time

def callback(n, loop):
    print(f‘callback {n} invoked at {loop.time()}‘)

async def main(loop):
    # 运行结果来看,这now是从0开始的
    now = loop.time()
    print(f‘clock time: {time.time()}‘)
    print(f‘loop  time {now}‘)
    print(‘registering callbacks‘)
    # 加0.2秒
    loop.call_at(now + .2, callback, 1, loop)
    # 加0.1 秒
    loop.call_at(now + .1, callback, 2, loop)
    # 马上开始
    loop.call_soon(callback, 3, loop)

    await asyncio.sleep(1)

event_loop = asyncio.get_event_loop()
try:
    print(‘entering event loop‘)
    event_loop.run_until_complete(main(event_loop))
finally:
    print(‘closing event loop‘)
    event_loop.close()
/usr/local/bin/python3.7 /Users/shijianzhong/study/t_asyncio/asynvio_call_at.py
entering event loop
clock time: 1579366496.336677
loop  time 0.086557153
registering callbacks
callback 3 invoked at 0.086701756
callback 2 invoked at 0.189241196
callback 1 invoked at 0.29037571
closing event loop

Process finished with exit code 0

原文地址:https://www.cnblogs.com/sidianok/p/12210857.html

时间: 2024-10-09 04:19:29

asyncio:异步I/O、事件循环和并发工具(持续跟新中)的相关文章

node.js的作用、回调、同步异步代码、事件循环

http://www.nodeclass.com/articles/39274 一.node.js的作用 I/O的意义,(I/O是输入/输出的简写,如:键盘敲入文本,输入,屏幕上看到文本显示输出.鼠标移动,在屏幕上看到鼠标的移动.终端的输入,和看到的输出.等等) node.js想解决的问题,(处理输入,输入,高并发 .如 在线游戏中可能会有上百万个游戏者,则有上百万的输入等等)(node.js适合的范畴:当应用程序需要在网络上发送和接收数据时Node.js最为适合.这可能是第三方的API,联网设

异步相关及事件循环

异步相关 1 // 今日头条面试题 2 async function async1() { 3 console.log('async1 start') 4 await async2() 5 console.log('async1 end') 6 } 7 async function async2() { 8 console.log('async2') 9 } 10 console.log('script start') 11 setTimeout(function () { 12 console

js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)

javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环中的同步任务,异步任务: 同步和异步任务在不同的执行"场所",同步的进入主线程,异步的进入Event Table执行并注册函数. 当指定的异步事情完成时,Event Table会将这个函数移入Event Queue. 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,推

QT中的线程与事件循环理解(2)

1. Qt多线程与Qobject的关系 每一个 Qt 应用程序至少有一个事件循环,就是调用了QCoreApplication::exec()的那个事件循环.不过,QThread也可以开启事件循环.只不过这是一个受限于线程内部的事件循环.因此我们将处于调用main()函数的那个线程,并且由QCoreApplication::exec()创建开启的那个事件循环成为主事件循环,或者直接叫主循环.注意,QCoreApplication::exec()只能在调用main()函数的线程调用.主循环所在的线程

乱谈Qt事件循环嵌套

本文旨在说明:QDialog::exec().QMenu::exec()等开启的局部事件循环,易用的背后,还有很多的陷阱... 引子 Qt 是事件驱动的,基本上,每一个Qt程序我们都会通过QCoreApplication或其派生类的exec()函数来开启事件循环(QEventLoop): int main(int argc, char**argv) { QApplication a(argc, argv); return a.exec(); } 但是在同一个线程内,我们可以开启多个事件循环,比如

【转】从settimeout说事件循环模型

原文地址:http://www.alloyteam.com/2015/10/turning-to-javascript-series-from-settimeout-said-the-event-loop-model/#prettyPhoto 作为一个从其他编程语言(C#/Java)转到Javascript的开发人员,在学习Javascript过程中,setTimeout()方法的运行原理是我遇到的一个不太好理解的部分,本文尝试结合其他编程语言的实现,从setTimeout说事件循环模型 1.从

【译】并发模型和事件循环

JavaScript有一个基于"事件循环"的并发模型.这种模型完全不同于从其他语言的,如C和java. 运行时的概念 下面的章节解释一个理论模型.现代JavaScript引擎实现和优化所描述的语义. 直观表示 栈 函数调用形成一个堆栈的帧. 当调用bar函数时,第一个帧被创建,它包含了bar的参数和局部变量.当bar调用foo时,第二个帧被创建并被推到第一个帧上,该第一个帧包含foo的参数和局部变量.返回时,顶部帧元素从堆栈中弹出(只留下bar的调用帧).当bar返回时,堆栈为空. 

JavaScipt 中的事件循环机制,以及微任务 和宏任务的概念

说事件循环(event loop)之前先要搞清楚几个问题. 1. js为什么是单线程的? 试想一下,如果js不是单线程的,同时有两个方法作用dom,一个删除,一个修改,那么这时候浏览器该听谁的?这就是js被设计成单线程的原因. 2.js为什么需要异步? 如果js不是异步的话,由于js代码本身是自上而下执行的,那么如果上一行代码需要执行很久,下面的代码就会被阻塞,对用户来说,就是"卡死",这样的话,会造成很差的用户体验. 3.js是如何实现异步的? 既然js是单线程的,那么js是如何实现

vue nextTick深入理解-vue性能优化、DOM更新时机、事件循环机制

一.定义[nextTick.事件循环] nextTick的由来: 由于VUE的数据驱动视图更新,是异步的,即修改数据的当下,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新. nextTick的触发时机: 在同一事件循环中的数据变化后,DOM完成更新,立即执行nextTick(callback)内的回调. 应用场景: 需要在视图更新之后,基于新的视图进行操作. 以上出现了事件循环的概念,其涉及到JS的运行机制,包括主线程的执行栈.异步队列.异步API.事件循环的协