笔记-python -asynio
笔记-python -asynio
1. 简介
asyncio是做什么的?
asyncio is a library to write concurrent code using the async/await syntax.
asyncio is used as a foundation for multiple Python asynchronous frameworks that provide high-performance network and web-servers, database connection libraries, distributed task queues, etc.
asyncio is often a perfect fit for IO-bound and high-levelstructured network code.
python3.0时代,标准库里的异步网络模块:select(非常底层) ,python3.0时代,第三方异步网络库:Tornado,python3.4时代,asyncio:支持TCP,子进程。
现在的asyncio,有了很多的模块已经在支持:
参考文档:python-3.6.5-docs-html/library/asyncio.html?highlight=async#module-asyncio
注:实验环境为python3.6.4,在3.7中asyncio有一定的新特性。
其实python3.6.5文档中asyncio资料学习曲线更人性化,看完它再看新版理解起来也很快。
2. base eventloop
code:Lib/asyncio/events.py
事件循环的基类,它是核心功能提供者,功能包括:
- 注册、执行和取消延迟调用;
- 创建不同客户和服务端联系;
- 与外部组件联系;
- 将函数放进线程执行;
2.1. run an event loop
一些行为和状态获取方法:
- AbstractEventLoop.run_forever()
Run until stop() is called.
- AbstractEventLoop.run_until_complete(future)
Run until the Future is done.
- AbstractEventLoop.is_running()
Returns running status of event loop.
- AbstractEventLoop.stop()
Stop running the event loop.
- AbstractEventLoop.is_closed()
Returns True if the event loop was closed.
- AbstractEventLoop.close()
Close the event loop. The loop must not be running. Pending callbacks will be lost.
This clears the queues and shuts down the executor, but does not wait for the executor to finish.
This is idempotent and irreversible. No other methods should be called after this one.
- coroutine AbstractEventLoop.shutdown_asyncgens()
Schedule all currently open asynchronous generator objects to close with an aclose() call. After calling this method, the event loop will issue a warning whenever a new asynchronous generator is iterated. Should be used to finalize all scheduled asynchronous generators reliably. Example:
3. event loops
code: Lib/asyncio/events.py
主要描述循环部分,核心是循环策略。
3.1. event loop functions
下面的函数是对全局策略的快捷访问,提供了默认选项。
asyncio.get_event_loop()
Equivalent to calling get_event_loop_policy().get_event_loop().
asyncio.set_event_loop(loop)
Equivalent to calling get_event_loop_policy().set_event_loop(loop).
asyncio.new_event_loop()
Equivalent to calling get_event_loop_policy().new_event_loop().
3.2. 事件循环策略
class asyncio.SelectorEventLoop
Event loop based on the selectors module. Subclass of AbstractEventLoop.
Use the most efficient selector available on the platform.
On Windows, only sockets are supported (ex: pipes are not supported): see the MSDN documentation of select.
class asyncio.ProactorEventLoop
Proactor event loop for Windows using “I/O Completion Ports” aka IOCP. Subclass of AbstractEventLoop.
Availability: Windows.
一般用户是不需要进行policy设置的。
class asyncio.AbstractEventLoopPolicy是策略类;
下面的函数可以查改全局策略:
asyncio.get_event_loop_policy()
Get the current event loop policy.
asyncio.set_event_loop_policy(policy)
Set the current event loop policy. If policy is None, the default policy is restored.
# 测试代码:
loop_policy = asyncio.get_event_loop_policy()
print(loop_policy)
# 输出:
<asyncio.windows_events._WindowsDefaultEventLoopPolicy
object at 0x0000003135046898>
4.
tasks and coroutines
Source code: Lib/asyncio/tasks.py
Source code: Lib/asyncio/coroutines.py
4.1.
coroutines
有两种声明方式:
- async def # 在3.5中新增
- generators 使用生成器应该用@asyncio.coroutine装饰
The word “coroutine”, like the word
“generator”, is used for two different (though related) concepts:
- The function that defines a
coroutine (a function definition using async def or decorated
with @asyncio.coroutine). If disambiguation is needed we will call this
a coroutine function (iscoroutinefunction() returns True). - The object obtained by calling
a coroutine function. This object represents a computation or an I/O operation
(usually a combination) that will complete eventually. If disambiguation is
needed we will call it a coroutine object (iscoroutine() returns True).
要做的事封装进一个函数(coroutine function)。
@asyncio.coroutine
它是一个修饰器,可能允许生成器使用yield from 调用asnyc def 协程,也可以允许生成器被async def 协程调用。但两者没必要同时使用。
代码示例:
@asyncio.coroutine
def hello5(name):
print(name)
yield from asyncio.sleep(2)
return
print(hello5)
print(hello5('ttt'))
loop = asyncio.get_event_loop()
loop.run_until_complete(hello5('uuuu'))
print(asyncio.sleep(2))
如果没有通过asyncio的接口调用协程,会导致异常
协程对象中可以做的事:
- result = await future or result = yield from future –
suspends the coroutine until the future is done, then returns the future’s
result, or raises an exception, which will be propagated. (If the future is
cancelled, it will raise a CancelledErrorexception.) Note that tasks are
futures, and everything said about futures also applies to tasks. - result = await coroutine or result = yield from coroutine –
wait for another coroutine to produce a result (or raise an exception, which
will be propagated). The coroutine expression must be
a call to another coroutine. - return expression –
produce a result to the coroutine that is waiting for this one using await or yield from. - raise exception –
raise an exception in the coroutine that is waiting for this one using await or yield from.
Calling a coroutine does not start its code
running – the coroutine object returned by the call doesn’t do anything until
you schedule its execution. There are two basic ways to start it running:
call await coroutine or yield from coroutine from
another coroutine (assuming the other coroutine is already running!), or
schedule its execution using the ensure_future() function or the AbstractEventLoop.create_task() method.
Coroutines (and tasks) can only run when
the event loop is running.
下面结合一些案例理解
import asyncio
async def hello_world():
print("Hello
World!")
loop
= asyncio.get_event_loop()
#
Blocking call which returns when the hello_world() coroutine is done
loop.run_until_complete(hello_world())
loop.close()
这个很简单,声明一个协程,获取循环,把协程放进循环运行,关闭循环。
import asyncio
import datetime
async def display_date(loop):
end_time = loop.time() + 5.0
while True:
print(datetime.datetime.now())
if (loop.time() + 1.0) >= end_time:
break
await asyncio.sleep(1)
loop
= asyncio.get_event_loop()
#
Blocking call which returns when the display_date() coroutine is done
loop.run_until_complete(display_date(loop))
loop.close()
每秒打一个日期值,持续5秒。
案例:
# 协程之间的切换
import asyncio
async def compute(x, y):
print("Compute %s + %s ..." % (x, y))
await asyncio.sleep(1.0)
return x + y
async def print_sum(x, y):
result = await compute(x,
y)
print("%s + %s = %s" % (x, y, result))
loop
= asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()
执行顺序图如下:
4.2.
future
class asyncio.Future(*, loop=None)
This
class is almost compatible with concurrent.futures.Future.
Differences:
result() and exception() do
not take a timeout argument and raise an exception when the future isn’t done
yet.
Callbacks
registered with add_done_callback() are always called via the event
loop’s call_soon().
This
class is not compatible with
the wait() and as_completed() functions in
the concurrent.futures package.
This
class is not thread safe.
方法:
- cancel()
Cancel the
future and schedule callbacks.
If the future
is already done or cancelled, return False. Otherwise, change the future’s
state to cancelled, schedule the callbacks and return True.
- cancelled()
Return True if
the future was cancelled.
- done()
Return True if
the future is done.
Done means
either that a result / exception are available, or that the future was
cancelled.
- result()
Return the
result this future represents.
If the future
has been cancelled, raises CancelledError. If the future’s result isn’t
yet available, raises InvalidStateError. If the future is done and has an
exception set, this exception is raised.
- exception()
Return the
exception that was set on this future.
The exception
(or None if no exception was set) is returned only if the future is
done. If the future has been cancelled, raises CancelledError. If the
future isn’t done yet, raises InvalidStateError.
- add_done_callback(fn)
Add a callback
to be run when the future becomes done.
The callback
is called with a single argument - the future object. If the future is already
done when this is called, the callback is scheduled with call_soon().
Use
functools.partial to pass parameters to the callback. For example,fut.add_done_callback(functools.partial(print, "Future:", flush=True)) will
call print("Future:", fut,flush=True).
- remove_done_callback(fn)
Remove all
instances of a callback from the “call when done” list.
Returns the
number of callbacks removed.
- set_result(result)
Mark the
future done and set its result.
If the future
is already done when this method is called, raises InvalidStateError.
- set_exception(exception)
Mark the
future done and set an exception.
If the future is already
done when this method is called, raises InvalidStateError.
案例:
import asyncio
async def slow_operation(future):
await asyncio.sleep(1)
future.set_result('Future is done!')
loop
= asyncio.get_event_loop()
future
= asyncio.Future()
asyncio.ensure_future(slow_operation(future))
loop.run_until_complete(future)
print(future.result())
loop.close()
案例:
使用了run_forever及stop。
import asyncio
async def slow_operation(future):
await asyncio.sleep(1)
future.set_result('Future is done!')
def got_result(future):
print(future.result())
loop.stop()
loop
= asyncio.get_event_loop()
future
= asyncio.Future()
asyncio.ensure_future(slow_operation(future))
future.add_done_callback(got_result)
try:
loop.run_forever()
finally:
loop.close()
4.3.
task
class asyncio.Task(coro, *, loop=None)
包装协程,是future的子类。
task是一个概念,是协程进一步的分解或调度。
取消task并不意味着取消future,但是取消task可能会导致future异常;
基本上task是一个ascio内部调度用的概念,不要直接创建task实例,使用ensure_future,或者AbstractEventLoop.create_task()
此类线程不是线程安全的。
方法:
- classmethod all_tasks(loop=None)
Return a set of all tasks for an event loop.
By default all tasks for the current event loop are
returned.
- classmethod current_task(loop=None)
Return the currently running task in an event loop
or None.
By default the current task for the current event loop
is returned.
None is returned when called not in the context of
a Task.
- cancel()
Request that this task cancel itself.
This arranges for a CancelledError to be
thrown into the wrapped coroutine on the next cycle through the event loop. The
coroutine then has a chance to clean up or even deny the request using
try/except/finally.
Unlike Future.cancel(), this does not guarantee
that the task will be cancelled: the exception might be caught and acted upon,
delaying cancellation of the task or preventing cancellation completely. The
task may also return a value or raise a different exception.
Immediately after this method is
called, cancelled() will not return True (unless the task
was already cancelled). A task will be marked as cancelled when the wrapped
coroutine terminates with a CancelledError exception (even
if cancel() was not called).
- get_stack(*, limit=None)
Return the list of stack frames for this task’s
coroutine.
- print_stack(*, limit=None, file=None)
- Print the stack or traceback
for this task’s coroutine.
4.4.
task functions
asyncio.as_completed(fs, *, loop=None, timeout=None)
Return an iterator whose values, when
waited for, are Future instances.
Raises asyncio.TimeoutError if
the timeout occurs before all Futures are done.
Example:
for f in as_completed(fs):
result = yield from f #
The 'yield from' may raise
# Use result
asyncio.ensure_future(coro_or_future, *, loop=None)
Schedule the execution of a coroutine
object: wrap it in a future. Return a Task object.
If the argument is a Future, it is returned
directly.
asyncio.gather(*coros_or_futures, loop=None, return_exceptions=False)
Return a future aggregating results from
the given coroutine objects or futures.
asyncio.iscoroutine(obj)
Return True if obj is
a coroutine object, which may be based on a generator or
an async def coroutine.
asyncio.iscoroutinefunction(func)
Return True if func is
determined to be a coroutine function, which may be a decorated generator
function or an asyncdef function.
asyncio.run_coroutine_threadsafe(coro, loop)
Submit a coroutine object to a
given event loop.
Return
a concurrent.futures.Future to access the result.
This function is meant to be called from a
different thread than the one where the event loop is running. Usage:
coroutine asyncio.sleep(delay, result=None, *, loop=None)
Create a coroutine that
completes after a given time (in seconds). If result is provided, it
is produced to the caller when the coroutine completes.
The resolution of the sleep depends on
the granularity
of the event loop.
This function is a coroutine.
coroutine asyncio.wait(futures, *, loop=None, timeout=None, return_when=ALL_COMPLETED)
可以指定return_when参数决定什么时候返回
Wait for the Futures and coroutine objects
given by the sequence futures to complete. Coroutines will be wrapped
in Tasks. Returns two sets of Future: (done, pending).
The sequence futures must not be
empty.
timeout can be used to control the
maximum number of seconds to wait before returning. timeout can be an
int or float. If timeout is not specified or None, there is no
limit to the wait time.
return_when indicates when this
function should return. It must be one of the following constants of the concurrent.futures module:
Constant |
Description |
FIRST_COMPLETED |
The function will return when any future |
FIRST_EXCEPTION |
The function will return when any future |
ALL_COMPLETED |
The function will return when all futures |
This function is a coroutine.
Usage:
done, pending = yield from asyncio.wait(fs)
Note
This does not raise asyncio.TimeoutError! Futures that aren’t done
when the timeout occurs are returned in the second set.
coroutine asyncio.wait_for(fut, timeout, *, loop=None)
Wait for the single Future or coroutine
object to complete with timeout. If timeout is None,
block until the future completes.
Coroutine will be wrapped in Task.
Returns result of the Future or coroutine.
When a timeout occurs, it cancels the task and raises asyncio.TimeoutError. To avoid the task
cancellation, wrap it in shield().
If the wait is cancelled, the
future fut is also cancelled.
This function is a coroutine,
usage:
result = yield from asyncio.wait_for(fut,
60.0)
Changed in version 3.4.3: If the wait
is cancelled, the future fut is now also cancelled.
5.
总结
asyncio的核心概念就是循环,future,task;其它的概念都是依附于这三个概念的。
基本上使用asyncio的过程描述如下:
- 获取循环,包括指定循环策略;
- 生成及注册future,添加callback
- 开始循环
- 有时需要把主线程留下来做交互,而在另一个线程进行事件循环asyncio.run_coroutine_threadsafe(coro, loop)
笔记-python -asynio的更多相关文章
- 笔记-python操作mysql
笔记-python操作mysql 1. 开始 1.1. 环境准备-mysql create database db_python; use db_python; create tabl ...
- 笔记-python异常信息输出
笔记-python异常信息输出 1. 异常信息输出 python异常捕获使用try-except-else-finally语句: 在except 语句中可以使用except as e,然后通 ...
- 笔记-python lib-pymongo
笔记-python lib-pymongo 1. 开始 pymongo是python版的连接库,最新版为3.7.2. 文档地址:https://pypi.org/project/pymong ...
- 笔记-python tutorial-9.classes
笔记-python tutorial-9.classes 1. Classes 1.1. scopes and namespaces namespace: A namespace is ...
- MongoDB学习笔记:Python 操作MongoDB
MongoDB学习笔记:Python 操作MongoDB Pymongo 安装 安装pymongopip install pymongoPyMongo是驱动程序,使python程序能够使用Mong ...
- 机器学习实战笔记(Python实现)-08-线性回归
--------------------------------------------------------------------------------------- 本系列文章为<机器 ...
- 机器学习实战笔记(Python实现)-05-支持向量机(SVM)
--------------------------------------------------------------------------------------- 本系列文章为<机器 ...
- 机器学习实战笔记(Python实现)-04-Logistic回归
--------------------------------------------------------------------------------------- 本系列文章为<机器 ...
- 机器学习实战笔记(Python实现)-03-朴素贝叶斯
--------------------------------------------------------------------------------------- 本系列文章为<机器 ...
随机推荐
- html table 的属性
表格table th,td 文字顶部对齐 <th valign="top"></th> <td valign="top">& ...
- bai_du 采集代码(已过期)
<?php $url = "http://www.baidu.com/s?wd=site:www.xxxxxx.com+inurl:hot&tn=baidulaonian&am ...
- 初看Mybatis 源码 (二) Java动态代理类
先抛出一个问题,用过Mybatis的都知道,我们只需要定义一个Dao的接口,在里面写上一些CRUD相关操作,然后配置一下sql映射文件,就可以达到调用接口中的方法,然后执行sql语句的效果,为什么呢? ...
- CAD出现向程序发送命令时出现问题提示解决方法分享
大家有没有遇到在使用cad打开图纸的时候提示向程序发送命令时出现错误的情况呢,如果你在使用cad的时候出现了这个提示,是由于软件的兼容性出现了问题,那么该怎么办呢,下面小编就给大家带来cad打开图纸提 ...
- 五环之歌之PHP分页
根据以往的经验,对于很多初学者,分页功能实现起来还是有一定的困难的,为了帮大家解决这样的问题:特此献上五环之歌.从此分页功能便是如小岳岳唱歌一样简练,漂亮,精干.哈哈,不闲扯了.正式进入千锋PHP五环 ...
- 【js基础修炼之路】- 手把手教你实现bind
手写bind前我们先回顾一下bind有哪些特性,以便更好的理解bind和实现bind. bind的特性 var obj = { a: 100, say(one, two) { console.log( ...
- Altium_Designer17-PCB-如何重新定义板子外形
当我们绘制完电路图.完成PCB布局和布线后,我们会遇到下面这种情况: 发现什么了吗?那么大的黑框框,我们只用到了很少的一部分.那有啥?告诉你黑框框的大小就是你最后将要印刷的PCB板的实际大小!大家都知 ...
- Top K问题-BFPRT算法、Parition算法
BFPRT算法原理 在BFPTR算法中,仅仅是改变了快速排序Partion中的pivot值的选取,在快速排序中,我们始终选择第一个元素或者最后一个元素作为pivot,而在BFPTR算法中,每次选择五分 ...
- 轻量级HTTP服务器Nginx(配置与调试Nginx维护Nginx)
轻量级HTTP服务器Nginx(配置与调试Nginx) 文章来源于南非蚂蚁 Nginx安装完毕后,会产生相应的安装目录,根据前面的安装路径,Nginx的配置文件路径为/opt/nginx/conf ...
- 【转】NodeJS教程--基于ExpressJS框架的文件上传
本文是翻译的一篇文章,原文地址:Handle File Uploads in Express (Node.js). 在NodeJS发展早期上传文件是一个较难操作的功能,随后出现了formidable. ...