1. # 【【异步IO】】
  2.  
  3. # 【协程】
  4.  
  5. '''
    协程,又称微线程,纤程。英文名Coroutine。
  6.  
  7. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用。
  8.  
  9. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。
  10.  
  11. 所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。
  12.  
  13. 子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。
  14.  
  15. 协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
  16.  
  17. 注意,在一个子程序中中断,去执行其他子程序,不是函数调用,有点类似CPU的中断。比如子程序A、B:
  18.  
  19. def A():
    print('1')
    print('2')
    print('3')
  20.  
  21. def B():
    print('x')
    print('y')
    print('z')
    假设由协程执行,在执行A的过程中,可以随时中断,去执行B,B也可能在执行过程中中断再去执行A,结果可能是:
  22.  
  23. 1
    2
    x
    y
    3
    z
    但是在A中是没有调用B的,所以协程的调用比函数调用理解起来要难一些。
  24.  
  25. 看起来A、B的执行有点像多线程,但协程的特点在于是一个线程执行,那和多线程比,协程有何优势?
  26.  
  27. 最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
  28.  
  29. 第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
  30.  
  31. 因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
  32.  
  33. Python对协程的支持是通过generator实现的。
  34.  
  35. 在generator中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。
  36.  
  37. 但是Python的yield不但可以返回一个值,它还可以接收调用者发出的参数。
  38.  
  39. '''
    # 例子
    '''
    传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。
    如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:
    '''
    def consumer():
    r = ''
    while True:
    n = yield r
    if not n:
    return
    print ('[Consumer] consuming %s...' % n)
    r = '200 ok'
    def produce(c):
    c.send(None)
    n = 0
    while n < 5:
    n = n + 1
    print ('[Producer] Producing %s...' % n)
    r = c.send(n)
    print ('[Producer] Consumer return %s...' % r)
    c.close()
    c = consumer()
    produce(c)
    '''
    [PRODUCER] Producing 1...
    [CONSUMER] Consuming 1...
    [PRODUCER] Consumer return: 200 OK
    [PRODUCER] Producing 2...
    [CONSUMER] Consuming 2...
    [PRODUCER] Consumer return: 200 OK
    [PRODUCER] Producing 3...
    [CONSUMER] Consuming 3...
    [PRODUCER] Consumer return: 200 OK
    [PRODUCER] Producing 4...
    [CONSUMER] Consuming 4...
    [PRODUCER] Consumer return: 200 OK
    [PRODUCER] Producing 5...
    [CONSUMER] Consuming 5...
    [PRODUCER] Consumer return: 200 OK
    '''
  40.  
  41. '''
    注意到consumer函数是一个generator,把一个consumer传入produce后:
  42.  
  43. 首先调用c.send(None)启动生成器;
  44.  
  45. 然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
  46.  
  47. consumer通过yield拿到消息,处理,又通过yield把结果传回;
  48.  
  49. produce拿到consumer处理的结果,继续生产下一条消息;
  50.  
  51. produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
  52.  
  53. 整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
  54.  
  55. 最后套用Donald Knuth的一句话总结协程的特点:
  56.  
  57. “子程序就是协程的一种特例。”
    '''
  58.  
  59. #【asyncio】
  60.  

#  例子

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

header = 'GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\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()))

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()

''' wget www.163.com...

wget www.sohu.com...

wget www.sina.com.cn...

www.sohu.com header > HTTP/1.1 200 OK

www.sohu.com header > Content-Type: text/html;charset=UTF-8

www.sohu.com header > Connection: close

www.sohu.com header > Server: nginx

www.sohu.com header > Date: Tue, 31 Jul 2018 07:44:25 GMT www.sohu.com header > Cache-Control: max-age=60 www.sohu.com header > X-From-Sohu: X-SRC-Cached www.sohu.com header > Content-Encoding: gzip www.sohu.com header > FSS-Cache: HIT from 10983758.13343064.18921842 www.sohu.com header > FSS-Proxy: Powered by 9541944.10459458.17480006 www.sina.com.cn header > HTTP/1.1 302 Moved Temporarily www.sina.com.cn header > Server: nginx www.sina.com.cn header > Date: Tue, 31 Jul 2018 07:45:18 GMT www.sina.com.cn header > Content-Type: text/html www.sina.com.cn header > Content-Length: 154 www.sina.com.cn header > Connection: close www.sina.com.cn header > Location: https://www.sina.com.cn/ www.sina.com.cn header > X-Via-CDN: f=edge,s=ctc.nanjing.ha2ts4.118.nb.sinaedge.com,c=180.168.212.46; www.sina.com.cn header > X-Via-Edge: 15330231186532ed4a8b47c5e66ca7c92596e www.163.com header > HTTP/1.1 200 OK www.163.com header > Expires: Tue, 31 Jul 2018 07:46:38 GMT www.163.com header > Date: Tue, 31 Jul 2018 07:45:18 GMT www.163.com header > Server: nginx www.163.com header > Content-Type: text/html; charset=GBK www.163.com header > Vary: Accept-Encoding,User-Agent,Accept www.163.com header > Cache-Control: max-age=80 www.163.com header > X-Via: 1.1 PSzjwzdx11jb78:2 (Cdn Cache Server V2.0), 1.1 zhoudianxin177:0 (Cdn Cache Server V2.0) www.163.com header > Connection: close

'''

'''

【解析】

asyncio.open_connection接受host参数和port参数以及一些可选的关键字参数.返回一个reader和一个writer,redaer is a StreamReader instance; the writer is a StreamWriter instance. writer.write就和socket.send差不多… drain的官方解释: drain() gives the opportunity for the loop to schedule the write operation and flush the buffer. It should especially be used when a possibly large amount of data is written to the transport, and the coroutine does not yield-from between calls to write(). 在事件循环中刷新缓冲区,特别是在数据量很大的情况下,保证数据完整性

'''

  1. # 【aiohttp】
    '''
    asyncio可以实现单线程并发IO操作。如果仅在客户端,发挥的威力不大。如果用在服务器端,例如Web服务器,由于HTTP连接就是IO操作,因此可以用单线程
    +coroutine实现多用户的高并发支持。
    asyncio实现了TCP、UDP、SSL等协议,aiohttp是基于asyncio实现的HTTP框架。
    '''
  2.  
  1. import asyncio
    from aiohttp import web
  2.  
  3. async def index(request):
    await asyncio.sleep(0.5)
    return web.Response(body=b'<h1>Index</h1>',content_type='text/html')
  4.  
  5. async def hello(request):
    await asyncio.sleep(0.5)
    text = '<h1>hello,%s!</h1>' % request.match_info['name']
    return web.Response(body=text.encode('utf-8'),content_type='text/html')
  6.  
  7. async def init(loop):
    app = web.Application(loop=loop)
    app.router.add_route('GET','/',index)
    app.router.add_route('GET','/hello/{name}',hello)
    srv = await loop.create_server(app.make_handler(),'127.0.0.1',8002)
    print ('Server started at http://127.0.0.1:8002.....')
    return srv
  8.  
  9. loop = asyncio.get_event_loop()
    loop.run_until_complete(init(loop))
    loop.run_forever()

【Python】【异步IO】的更多相关文章

  1. Python异步IO --- 轻松管理10k+并发连接

    前言   异步操作在计算机软硬件体系中是一个普遍概念,根源在于参与协作的各实体处理速度上有明显差异.软件开发中遇到的多数情况是CPU与IO的速度不匹配,所以异步IO存在于各种编程框架中,客户端比如浏览 ...

  2. python异步IO编程(一)

    python异步IO编程(一) 基础概念 协程:python  generator与coroutine 异步IO (async IO):一种由多种语言实现的与语言无关的范例(或模型). asyncio ...

  3. python异步IO编程(二)

    python异步IO编程(二) 目录 开门见山 Async IO设计模式 事件循环 asyncio 中的其他顶层函数 开门见山 下面我们用两个简单的例子来让你对异步IO有所了解 import asyn ...

  4. Python - 异步IO\数据库\队列\缓存

    协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程,协程一定是在单线程运行的. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和 ...

  5. Python异步IO

    在IO操作的过程中,当前线程被挂起,而其他需要CPU执行的代码就无法被当前线程执行了. 我们可以使用多线程或者多进程来并发执行代码,为多个用户服务. 但是,一旦线程数量过多,CPU的时间就花在线程切换 ...

  6. python -- 异步IO 协程

    python 3.4 >>> import asyncio >>> from datetime import datetime >>> @asyn ...

  7. Python异步IO之协程(一):从yield from到async的使用

    引言:协程(coroutine)是Python中一直较为难理解的知识,但其在多任务协作中体现的效率又极为的突出.众所周知,Python中执行多任务还可以通过多进程或一个进程中的多线程来执行,但两者之中 ...

  8. Python 异步IO、IO多路复用

    事件驱动模型 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  9. python 异步IO

    参考链接:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143208573 ...

  10. python 异步IO(syncio) 协程

    python asyncio 网络模型有很多中,为了实现高并发也有很多方案,多线程,多进程.无论多线程和多进程,IO的调度更多取决于系统,而协程的方式,调度来自用户,用户可以在函数中yield一个状态 ...

随机推荐

  1. node.js核心技术

    一.知识结构: http模块:配置简单 的web服务,npm/cnpm工具 express框架:express中间件进行服务配置:路由:请求处理: DB服务:学习使用mysql关系型数据库: web接 ...

  2. 51Nod 1049 最大子段和

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1049 #include<iostream> #i ...

  3. bzoj1625 [Usaco2007 Dec]宝石手镯

    01背包 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring& ...

  4. 系统批量运维管理器Fabric详解

    系统批量运维管理器Fabric详解 Fabrici 是基于python现实的SSH命令行工具,简化了SSH的应用程序部署及系统管理任务,它提供了系统基础的操作组件,可以实现本地或远程shell命令,包 ...

  5. TensorFlow 分布式实践

    此wiki主要介绍分布式环境使用的一些条件,一直所要注意的内容: 确保在此之前阅读过TensorFlow for distributed 1.集群描述 当前tensorflow 的版本(0.8.0), ...

  6. flask框架----flask入门

    一.Flask介绍(轻量级的框架,非常快速的就能把程序搭建起来) Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是 ...

  7. 使用Wisdom RESTClient进行自动化测试,如何取消对返回的body内容的校验?对排除的JSON属性字段不做校验?

    使用 Wisdom RESTClient 进行自动化测试 REST API,默认是对返回HTTP状态码和body内容都进行严格匹配和校验. (1). 如果每次触发API返回的body内容是动态变化的, ...

  8. react将表格动态生成视频列表【代码】【案例】

    只需要创建一个表格,id为videos,react就能将这个表格转换成视频列表,并点击自动播放 index.html <!DOCTYPE html> <html> <he ...

  9. Django里自定义用户登陆及登陆后跳转到登陆前页面的实现

    def logout(request): request.session.flush() return HttpResponseRedirect(request.META.get('HTTP_REFE ...

  10. pxc集群进入非主模式怎么让最后的节点允许提供服务

    这种情况一般是,集群其他节点意外宕机而最后一个节点无法自我仲裁,而进入非主模式. 该模式拒绝任何SQL的执行: ERROR 1047 (08S01): WSREP has not yet prepar ...