Python学习:异步IO:协程和asyncio
2016-03-26 14:51
639 查看
所谓协程就是在一个线程中切换子进程,相比多线程有如下好处:最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
python的协程通过generator支持的.
yield可以接受参数|传递参数.
send调用协程,第一次要使用send(None)启动generator.
下面使用协程实现简单的生产者-效果者模型.
def consumer(): r = '' while True: n = yield r if not n:return print('consuming the event %s'%n) r = '200 OK' def produce(c): c.send(None) for n in range(1,6): print('producing event %s'%n) r = c.send(n) print('the consumer response %s'%r) c.close() c = consumer() produce(c)
总结一下,线程就是特殊的协程.
但是只有协程还不够,还不足以实现异步IO,我们必须实现消息循环和状态的控制.这就要引入asynico,它直接内置了对异步IO的支持.asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
[0]:先看一个例子:
import asyncio,sys,time @asyncio.coroutine def hello(): time.sleep(3) print("Hello world!") # 异步调用asyncio.sleep(1): r = yield from asyncio.sleep(2) print("Hello again!") # 获取EventLoop: loop = asyncio.get_event_loop() # 执行coroutine loop.run_until_complete(asyncio.wait([hello() for i in range(3)])) loop.close()
在这个例子中,可以发现一旦协程阻塞,就会中断当前的协程处理,然后切换到下一个消息处理,同时把阻塞的协程加入消息队列的后面.
注意,如果是你自己写的协程,eventloop好像会直接执行yield from后面的协程,不管该协程是否有阻塞的行为(可能不能识别?)具体怎么处理还没有学习到,以后再更新
下面是使用协程来实现异步网络连接:
import asyncio @asyncio.coroutine def wget(host): print('wget %s...' % host) connect = asyncio.open_connection(host, 80) reader, writer = yield from connect header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host writer.write(header.encode('utf-8')) yield from writer.drain() while True: line = yield from reader.readline() if line == b'\r\n': break print('%s header > %s' % (host, line.decode('utf-8').rstrip())) # Ignore the body, close the socket writer.close() loop = asyncio.get_event_loop() tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']] loop.run_until_complete(asyncio.wait(tasks)) loop.close()
[0]asyncio.open_connection接受host参数和port参数以及一些可选的关键字参数.返回一个reader和一个writer,redaer is a StreamReader instance; the writer is a StreamWriter instance.
writer.write就和socket.send差不多…
[1]:对于writer.drain()的用法,它会阻塞如果writer的buffer已经满了…当然在我们这个例子里面buffer是充足的,因为我们只发送了几个GET请求。
When the size of the transport buffer reaches the high-water limit (the protocol is paused), block until the size of the buffer is drained down to the low-water limit and the protocol is resumed. When there is nothing to wait for, the yield-from continues immediately.相关文章推荐
- Pyhton: abs() 函数
- Python_模拟登陆新浪微博
- ubuntu下升级python
- Windows下IPython的配置安装
- Python在线笔试琐碎
- python 输出冒号;引号嵌套问题
- 中文Windows下用Python修改MAC地址
- 练习5:python的格式化字符
- 【资源汇集.转】Python 学习资源
- 17. Letter Combinations of a Phone Number
- python从零安装
- python--函数每天熟悉一个
- Python and or ?A:B
- Python——sorted
- Json概述以及python对json的相关操作
- Python MySQLdb 使用utf-8 编码插入中文数据
- LeetCode 292. Nim Game
- Python学习笔记(一)——Python函数的定义和使用
- python 标准类型内建函数
- 共有11款Python 中文分词库开源软件