一、简介

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。

asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO

此模块为编写单线程并发代码提高基础架构,通过使用协程、套接字和其他资源的 I/O 多路复用,运行网络客户端和服务器,以及其他相关的基元。

包内容的详细的列表如下:

  • 各种系统具体实现的可插拔 event loop
  • transport 和 protocol 抽象(类似于 Twisted 里的那些)
  • 具体支持 TCP、 UDP、 SSL、 子进程管道,延迟调用,和其他 (有些可能依赖于系统)
  • 一个模仿 concurrent.futures 模块但适合在事件循环中使用的 Future 类
  • 基于 yield from ( PEP 380)的协程和任务帮助以顺序的方式编写并发代码
  • 取消 Future 和协程的操作支持
  • 单线程的协程间使用的 synchronization primitives 类似于 threading 模块里那些
  • 一个接口,用于将工作传递到线程池,在绝对的时候,积极地使用一个阻塞I / O调用的库

二、参考文档

中文文档:http://python.usyiyi.cn/translate/python_352/library/asyncio.html

官方文档:https://docs.python.org/3/library/asyncio.html

三、关键示例

关于asyncio模块详细使用说明这里不再赘述,下面将为大家展示一些例子,作为快速学习之用:

1、使用 AbstractEventLoop.call_soon() 方法来安排回调的示例。回调显示 "Hello World",然后停止事件循环:

import asyncio

def hello_world(loop):
print('Hello World')
loop.stop() loop = asyncio.get_event_loop() # Schedule a call to hello_world()
loop.call_soon(hello_world, loop) # Blocking call interrupted by loop.stop()
loop.run_forever()
loop.close()

2、回调示例每​​秒显示当前日期。回调使用AbstractEventLoop.call_later()方法在5秒内重新计划自身,然后停止事件循环:

import asyncio
import datetime def display_date(end_time, loop):
print(datetime.datetime.now())
if (loop.time() + 1.0) < end_time:
loop.call_later(1, display_date, end_time, loop)
else:
loop.stop() loop = asyncio.get_event_loop() # Schedule the first call to display_date()
end_time = loop.time() + 5.0
loop.call_soon(display_date, end_time, loop) # Blocking call interrupted by loop.stop()
loop.run_forever()
loop.close()

3、等待文件描述器使用AbstractEventLoop.add_reader()方法接收到一些数据,然后关闭事件循环:

import asyncio
try:
from socket import socketpair
except ImportError:
from asyncio.windows_utils import socketpair # Create a pair of connected file descriptors
rsock, wsock = socketpair()
loop = asyncio.get_event_loop() def reader():
data = rsock.recv(100)
print("Received:", data.decode())
# We are done: unregister the file descriptor
loop.remove_reader(rsock)
# Stop the event loop
loop.stop() # Register the file descriptor for read event
loop.add_reader(rsock, reader) # Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode()) # Run the event loop
loop.run_forever() # We are done, close sockets and the event loop
rsock.close()
wsock.close()
loop.close()

4、使用AbstractEventLoop.add_signal_handler()方法的信号SIGINTSIGTERM的寄存器处理程序:

import asyncio
import functools
import os
import signal def ask_exit(signame):
print("got signal %s: exit" % signame)
loop.stop() loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
loop.add_signal_handler(getattr(signal, signame),
functools.partial(ask_exit, signame)) print("Event loop running forever, press Ctrl+C to interrupt.")
print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid())
try:
loop.run_forever()
finally:
loop.close() #此示例仅适用于UNIX

5、组合Futurecoroutine function的示例:

协程函数负责计算(需要1秒),并将结果存储到Futurerun_until_complete()方法等待Future的完成。

import asyncio

@asyncio.coroutine
def slow_operation(future):
yield from 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()

6、使用Future.add_done_callback()方法来不同地编写前面的示例来明确描述控制流:

在此示例中,Future用于将slow_operation()链接到got_result():当slow_operation()完成时,got_result()与结果一起调用。

import asyncio

@asyncio.coroutine
def slow_operation(future):
yield from 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()

7、并行执行3个任务(A,B,C)的示例:

任务在创建时自动计划执行。所有任务完成后,事件循环停止。

import asyncio

@asyncio.coroutine
def factorial(name, number):
f = 1
for i in range(2, number+1):
print("Task %s: Compute factorial(%s)..." % (name, i))
yield from asyncio.sleep(1)
f *= i
print("Task %s: factorial(%s) = %s" % (name, number, f)) loop = asyncio.get_event_loop()
tasks = [
asyncio.ensure_future(factorial("A", 2)),
asyncio.ensure_future(factorial("B", 3)),
asyncio.ensure_future(factorial("C", 4))]
loop.run_until_complete(asyncio.gather(*tasks))
loop.close()

output:

Task A: Compute factorial(2)...
Task B: Compute factorial(2)...
Task C: Compute factorial(2)...
Task A: factorial(2) = 2
Task B: Compute factorial(3)...
Task C: Compute factorial(3)...
Task B: factorial(3) = 6
Task C: Compute factorial(4)...
Task C: factorial(4) = 24

8、TCP echo客户端使用AbstractEventLoop.create_connection()方法,TCP回显服务器使用AbstractEventLoop.create_server()方法

客户端:

事件循环运行两次。在这个简短的例子中,优先使用run_until_complete()方法来引发异常,如果服务器没有监听,而不必写一个短的协程来处理异常并停止运行循环。在run_until_complete()退出时,循环不再运行,因此在发生错误时不需要停止循环。

import asyncio

class EchoClientProtocol(asyncio.Protocol):
def __init__(self, message, loop):
self.message = message
self.loop = loop def connection_made(self, transport):
transport.write(self.message.encode())
print('Data sent: {!r}'.format(self.message)) def data_received(self, data):
print('Data received: {!r}'.format(data.decode())) def connection_lost(self, exc):
print('The server closed the connection')
print('Stop the event loop')
self.loop.stop() loop = asyncio.get_event_loop()
message = 'Hello World!'
coro = loop.create_connection(lambda: EchoClientProtocol(message, loop),
'127.0.0.1', 8888)
loop.run_until_complete(coro)
loop.run_forever()
loop.close()

服务器:

Transport.close()可以在WriteTransport.write()之后立即调用,即使数据尚未在套接字上发送:两种方法都是异步的。不需要yield from,因为这些传输方法不是协程。

import asyncio

class EchoServerClientProtocol(asyncio.Protocol):
def connection_made(self, transport):
peername = transport.get_extra_info('peername')
print('Connection from {}'.format(peername))
self.transport = transport def data_received(self, data):
message = data.decode()
print('Data received: {!r}'.format(message)) print('Send: {!r}'.format(message))
self.transport.write(data) print('Close the client socket')
self.transport.close() loop = asyncio.get_event_loop()
# Each client connection will create a new protocol instance
coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888)
server = loop.run_until_complete(coro) # Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass # Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

9、UDP echo客户端使用AbstractEventLoop.create_datagram_endpoint()方法,UDP echo服务器使用AbstractEventLoop.create_datagram_endpoint()方法

客户端:

import asyncio

class EchoClientProtocol:
def __init__(self, message, loop):
self.message = message
self.loop = loop
self.transport = None def connection_made(self, transport):
self.transport = transport
print('Send:', self.message)
self.transport.sendto(self.message.encode()) def datagram_received(self, data, addr):
print("Received:", data.decode()) print("Close the socket")
self.transport.close() def error_received(self, exc):
print('Error received:', exc) def connection_lost(self, exc):
print("Socket closed, stop the event loop")
loop = asyncio.get_event_loop()
loop.stop() loop = asyncio.get_event_loop()
message = "Hello World!"
connect = loop.create_datagram_endpoint(
lambda: EchoClientProtocol(message, loop),
remote_addr=('127.0.0.1', 9999))
transport, protocol = loop.run_until_complete(connect)
loop.run_forever()
transport.close()
loop.close()

服务器:

import asyncio

class EchoServerProtocol:
def connection_made(self, transport):
self.transport = transport def datagram_received(self, data, addr):
message = data.decode()
print('Received %r from %s' % (message, addr))
print('Send %r to %s' % (message, addr))
self.transport.sendto(data, addr) loop = asyncio.get_event_loop()
print("Starting UDP server")
# One protocol instance will be created to serve all client requests
listen = loop.create_datagram_endpoint(
EchoServerProtocol, local_addr=('127.0.0.1', 9999))
transport, protocol = loop.run_until_complete(listen) try:
loop.run_forever()
except KeyboardInterrupt:
pass transport.close()
loop.close()

10、等待套接字使用协议使用AbstractEventLoop.create_connection()方法接收数据,然后关闭事件循环

import asyncio
try:
from socket import socketpair
except ImportError:
from asyncio.windows_utils import socketpair # Create a pair of connected sockets
rsock, wsock = socketpair()
loop = asyncio.get_event_loop() class MyProtocol(asyncio.Protocol):
transport = None def connection_made(self, transport):
self.transport = transport def data_received(self, data):
print("Received:", data.decode()) # We are done: close the transport (it will call connection_lost())
self.transport.close() def connection_lost(self, exc):
# The socket has been closed, stop the event loop
loop.stop() # Register the socket to wait for data
connect_coro = loop.create_connection(MyProtocol, sock=rsock)
transport, protocol = loop.run_until_complete(connect_coro) # Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode()) # Run the event loop
loop.run_forever() # We are done, close sockets and the event loop
rsock.close()
wsock.close()
loop.close()

11、TCP回显客户端使用asyncio.open_connection()函数,TCP回显服务器使用asyncio.start_server()函数

客户端:

import asyncio

@asyncio.coroutine
def tcp_echo_client(message, loop):
reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888,
loop=loop) print('Send: %r' % message)
writer.write(message.encode()) data = yield from reader.read(100)
print('Received: %r' % data.decode()) print('Close the socket')
writer.close() message = 'Hello World!'
loop = asyncio.get_event_loop()
loop.run_until_complete(tcp_echo_client(message, loop))
loop.close()

服务器:

import asyncio

@asyncio.coroutine
def handle_echo(reader, writer):
data = yield from reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print("Received %r from %r" % (message, addr)) print("Send: %r" % message)
writer.write(data)
yield from writer.drain() print("Close the client socket")
writer.close() loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
server = loop.run_until_complete(coro) # Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass # Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

12、在命令行中获取URL的HTTP头的简单示例:

import asyncio
import urllib.parse
import sys @asyncio.coroutine
def print_http_headers(url):
url = urllib.parse.urlsplit(url)
if url.scheme == 'https':
connect = asyncio.open_connection(url.hostname, 443, ssl=True)
else:
connect = asyncio.open_connection(url.hostname, 80)
reader, writer = yield from connect
query = ('HEAD {path} HTTP/1.0\r\n'
'Host: {hostname}\r\n'
'\r\n').format(path=url.path or '/', hostname=url.hostname)
writer.write(query.encode('latin-1'))
while True:
line = yield from reader.readline()
if not line:
break
line = line.decode('latin1').rstrip()
if line:
print('HTTP header> %s' % line) # Ignore the body, close the socket
writer.close() url = sys.argv[1]
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(print_http_headers(url))
loop.run_until_complete(task)
loop.close()
#用法:

python example.py http://example.com/path/page.html

#使用HTTPS:

python example.py https://example.com/path/page.html

13、协程等待,直到套接字使用open_connection()函数接收数据:

import asyncio
try:
from socket import socketpair
except ImportError:
from asyncio.windows_utils import socketpair @asyncio.coroutine
def wait_for_data(loop):
# Create a pair of connected sockets
rsock, wsock = socketpair() # Register the open socket to wait for data
reader, writer = yield from asyncio.open_connection(sock=rsock, loop=loop) # Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode()) # Wait for data
data = yield from reader.read(100) # Got data, we are done: close the socket
print("Received:", data.decode())
writer.close() # Close the second socket
wsock.close() loop = asyncio.get_event_loop()
loop.run_until_complete(wait_for_data(loop))
loop.close()

14、子进程协议的示例,用于获取子进程的输出并等待子进程退出。子过程由AbstractEventLoop.subprocess_exec()方法创建:

import asyncio
import sys class DateProtocol(asyncio.SubprocessProtocol):
def __init__(self, exit_future):
self.exit_future = exit_future
self.output = bytearray() def pipe_data_received(self, fd, data):
self.output.extend(data) def process_exited(self):
self.exit_future.set_result(True) @asyncio.coroutine
def get_date(loop):
code = 'import datetime; print(datetime.datetime.now())'
exit_future = asyncio.Future(loop=loop) # Create the subprocess controlled by the protocol DateProtocol,
# redirect the standard output into a pipe
create = loop.subprocess_exec(lambda: DateProtocol(exit_future),
sys.executable, '-c', code,
stdin=None, stderr=None)
transport, protocol = yield from create # Wait for the subprocess exit using the process_exited() method
# of the protocol
yield from exit_future # Close the stdout pipe
transport.close() # Read the output which was collected by the pipe_data_received()
# method of the protocol
data = bytes(protocol.output)
return data.decode('ascii').rstrip() if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop() date = loop.run_until_complete(get_date(loop))
print("Current date: %s" % date)
loop.close()

15、使用Process类控制子进程和StreamReader类从标准输出读取的示例。子过程由create_subprocess_exec()函数创建:

import asyncio.subprocess
import sys @asyncio.coroutine
def get_date():
code = 'import datetime; print(datetime.datetime.now())' # Create the subprocess, redirect the standard output into a pipe
create = asyncio.create_subprocess_exec(sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
proc = yield from create # Read one line of output
data = yield from proc.stdout.readline()
line = data.decode('ascii').rstrip() # Wait for the subprocess exit
yield from proc.wait()
return line if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop() date = loop.run_until_complete(get_date())
print("Current date: %s" % date)
loop.close()

 

  

asyncio的更多相关文章

  1. Python标准模块--asyncio

    1 模块简介 asyncio模块作为一个临时的库,在Python 3.4版本中加入.这意味着,asyncio模块可能做不到向后兼容甚至在后续的Python版本中被删除.根据Python官方文档,asy ...

  2. Asyncio中的Task管理

    #!/usr/bin/env python # -*- coding: utf-8 -*- import asyncio import datetime import time from random ...

  3. 使用Asyncio的Coroutine来实现一个有限状态机

    如图: #!/usr/bin/env python # -*- coding: utf-8 -*- import asyncio import datetime import time from ra ...

  4. 在PYTHON3中,使用Asyncio来管理Event loop

    #!/usr/bin/env python # -*- coding: utf-8 -*- import asyncio import datetime import time def functio ...

  5. Python asyncio库的学习和使用

    因为要找工作,把之前自己搞的爬虫整理一下,没有项目经验真蛋疼,只能做这种水的不行的东西...T  T,希望找工作能有好结果. 之前爬虫使用的是requests+多线程/多进程,后来随着前几天的深入了解 ...

  6. python asyncio笔记

    1.什么是coroutine coroutine,最早我是在lua里面看到的,coroutine最大的好处是可以保存堆栈,让程序得以继续执行,在python里面,一般是利用yield来实现,具体可以看 ...

  7. Tornado (and Twisted) in the age of asyncio》

    Tornado (and Twisted) in the age of asyncio>

  8. 【译】深入理解python3.4中Asyncio库与Node.js的异步IO机制

    转载自http://xidui.github.io/2015/10/29/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3python3-4-Asyncio%E5%BA%93% ...

  9. PYTHON ASYNCIO: FUTURE, TASK AND THE EVENT LOOP

    from :http://masnun.com/2015/11/20/python-asyncio-future-task-and-the-event-loop.html Event Loop On ...

  10. Understanding Asynchronous IO With Python 3.4's Asyncio And Node.js

    [转自]http://sahandsaba.com/understanding-asyncio-node-js-python-3-4.html Introduction I spent this su ...

随机推荐

  1. [MySQL]mysql指定路径启动

    /usr/sbin/mysqld --defaults-file=/etc/mysql/my.cnf --basedir=/usr --datadir=/var/lib/mysql --pid-fil ...

  2. leetcode-006 detect cycle

    package leetcode; public class DetectCycle { public ListNode detectCycle(ListNode head) { ListNode s ...

  3. Delphi中使用Dos窗口输出调试信息

    在项目文件 *.DPR (Project->View Source)  里加上{$APPTYPE   CONSOLE} 然后,在需要输出处加上 Writeln(‘your debug messa ...

  4. sql语句:if exists语句使用

    ') begin print('exists ') end else begin print('no exists ') end go

  5. C语言-结构体

    C语言中数组是把相同类型的数据类型的变量集中在一起了,而结构体则是把不同类型的变量聚集在一起. 结构体也是一种数据类型,但是它是一种自定义的数据类型,也就是说和使用其他数据类型不一样,我们得先定义这种 ...

  6. 多层神经网络BP算法 原理及推导

    首先什么是人工神经网络?简单来说就是将单个感知器作为一个神经网络节点,然后用此类节点组成一个层次网络结构,我们称此网络即为人工神经网络(本人自己的理解).当网络的层次大于等于3层(输入层+隐藏层(大于 ...

  7. django学习——url的name

    html中的地址可以用写死的,也可以用生成的,如:<a href="{% url 'app-url' param1 param2 ... %}">link</a& ...

  8. iOS 之 微信开发流程

    第1阶段 注册开放平台帐号 注册成为微信开放平台开发者 立即注册 认证开发者资质 开发者资质认证通过后才可申请微信支付,申请审核服务费:300元/次 立即认证 创建APP并提交审核 提交你的APP基本 ...

  9. Php连接及读取和写入mysql数据库的常用代码

    在这里我总结了常用的PHP连接MySQL数据库以及读取写入数据库的方法,希望能够帮到你,当然也是作为我自己的一个回顾总结. 1.为了更好地设置数据连接,一般会将数据连接所涉及的值定义成变量. $mys ...

  10. 天兔(Lepus)监控系统快速安装部署

    Lepus安装需要Lamp环境,Lamp环境的安装个人认为比较费劲,XAMPP的一键部署LAMP环境省心省力, lepus官网手册也建议采用XAMPP的方式安装,lepus也是在XAMPP上进行研发的 ...