Python协程实践分享

目录
  • 协程
  • yield在协程中的用法
    • 经典示例
  • 生产者-消费者模式(协程)
  • gevent第三方库协程支持
    • 经典代码
  • asyncio内置库协程支持
  • 关于aiohttp

协程

协程简单来说就是一个更加轻量级的线程,并且不由操作系统内核管理,完全由程序所控制(在用户态执行)。协程在子程序内部是可中断的,然后转而执行其他子程序,在适当的时候返回过来继续执行。

协程的优势?(协程拥有自己的寄存器上下文和栈,调度切换时,寄存器上下文和栈保存到其他地方,在切换回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文非常快。)

yield在协程中的用法

1、协程中的yield通常出现在表达式的右边:

x = yield data

如果yield的右边没有表达式,默认产出的值是None,现在右边有表达式,所以返回的是data这个值。
2、协程可以从调用法接受数据,调用通过send(x)方式将数据提供给协程,同时send方法中包含next方法,所以程序会继续执行。
3、协程可以
中断执行
,去执行另外的协程。

经典示例

代码:

def hello():
    data = "mima"
    while True:
        x = yield data
        print(x)
a = hello()
next(a)
data = a.send("hello")
print(data)

代码详解:
程序开始执行,函数hello不会真的执行,而是返回一个生成器给a。
当调用到next()方法时,hello函数才开始真正执行,执行print方法,继续进入while循环;
程序遇到yield关键字,程序再次中断,此时执行到a.send(“hello”)时,程序会从yield关键字继续向下执行,然后又再次进入while循环,再次遇到yield关键字,程序再次中断;

协程在运行过程中的四个状态

  • GEN_CREATE:等待开始执行
  • GEN_RUNNING:解释器正在执行
  • GEN_SUSPENDED:在yield表达式处暂停
  • GEN_CLOSED:执行结束

生产者-消费者模式(协程)

import time
def consumer():
    r = ""
    while True:
        res = yield r
        if not res:
            print("Starting.....")
            return
        print("[CONSUMER] Consuming %s...." %res)
        time.sleep(1)
        r = "200 OK"
def produce(c):
    next(c)
    n = 0
    while n<6:
        n+=1
        print("[PRODUCER] Producing %s ...."%n)
        r = c.send(n)
        print("[CONSUMER] Consumer return: %s ...."%r)
    c.close()
c = consumer()
produce(c)     

代码分析:

  • 调用next©启动生成器;
  • 消费者一旦生产东西,通过c.send切换到消费者consumer执行;
  • consumer通过yield关键字获取到消息,在通过yield把结果执行;
  • 生产者拿到消费者处理过的结果,继续生成下一条消息;
  • 当跳出循环后,生产者不生产了,通过close关闭消费者,整个过程结束;

gevent第三方库协程支持

原理:gevent基于协程的Python网络库,当一个greenlet遇到IO操作(访问网络)自动切换到其他的greenlet等到IO操作完成后,在适当的时候切换回来继续执行。换而言之就是greenlet通过帮我们自动切换协程,保证有greenlet在运行,而不是一直等待IO操作。

经典代码

由于切换时在发生IO操作时自动完成,所以gevent需要修改Python内置库,这里可以打上猴子补丁(用来在运行时动态修改已有的代码,而不需要原有的代码)monkey.patch_all

#!/usr/bin/python2
# coding=utf8
from gevent import monkey
monkey.patch_all()
import gevent
import requests
def handle_html(url):
    print("Starting %s。。。。" % url)
    response = requests.get(url)
    code = response.status_code
    print("%s: %s" % (url, str(code)))
if __name__ == "__main__":
    urls = ["https://www.baidu.com", "https://www.douban.com", "https://www.qq.com"]
    jobs = [ gevent.spawn(handle_html, url) for url in urls ]
    gevent.joinall(jobs)

运行结果:

结果:3个网络连接并发执行,但是结束的顺序不同。

asyncio内置库协程支持

原理:asyncio的编程模型就是一个消息循环,从asyncio模块中直接获取一个Eventloop(事件循环)的应用,然后把需要执行的协程放入EventLoop中执行,实现异步IO。

经典代码:

import asyncio
import threading
async def hello():
    print("hello, world: %s"%threading.currentThread())
    await asyncio.sleep(1) #
    print('hello, man %s'%threading.currentThread())

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait([hello(), hello()]))
    loop.close()

代码解析:

  • 首先获取一个EventLoop
  • 然后将这个hello的协程放进EventLoop,运行EventLoop,它会运行知道future被完成
  • hello协程内部执行await asyncio.sleep(1)模拟耗时1秒的IO操作,在此期间,主线程并未等待,而是去执行EventLoop中的其他线程,实现并发执行。

代码结果:

异步爬虫实例:

#!/usr/bin/python3
import aiohttp
import asyncio
async def fetch(url, session):
    print("starting: %s" % url)
    async with session.get(url) as response:
        print("%s : %s" % (url,response.status))
        return await response.read()
async def run():
    urls = ["https://www.baidu.com", "https://www.douban.com", "http://www.mi.com"]
    tasks = []
    async with aiohttp.ClientSession() as session:
        tasks = [asyncio.ensure_future(fetch(url, session)) for url in urls] # 创建任务
        response = await asyncio.gather(*tasks) # 并发执行任务

        for body in response:
            print(len(response))
if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run())
    loop.close()

代码解析:

  • 创建一个事件循环,然后将任务放到时间循环中;
  • run()方法中主要是创建任务,并发执行任务,返回读取到的网页内容;
  • fetch()方法通过aiohttp发出指定的请求,以及返回 可等待对象;

(结束输出网址和list中网址的顺序不同,证明协程中异步I/O操作)

关于aiohttp

asyncio实现类TCP、UDP、SSL等协议,aiohttp则是基于asyncio实现的HTTP框架,由此可以用来编写一个微型的HTTP服务器。

代码:

from aiohttp import web
async def index(request):
    await asyncio.sleep(0.5)
    print(request.path)
    return web.Response(body=' Hello, World')
async def hello(request):
    await asyncio.sleep(0.5)
    text = 'hello, %s'%request.match_info['name']
    print(request.path)
    return web.Response(body=text.encode('utf-8'))

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', 8000)
    print("Server started at http://127.0.0.0.1:8000....")
    return srv

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(init(loop))
    loop.run_forever()

代码解析:

  • 创建一个事件循环,传入到init协程中;
  • 创建Application实例,然后添加路由处理指定的请求;
  • 通过loop创建TCP服务,最后启动事件循环;

到此这篇关于Python协程实践分享的文章就介绍到这了,更多相关Python协程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一篇文章带你了解Python的进程,线程和协程

    目录 线程 线程锁 threading.RLock和threading.Lock 的区别 threading.Event threading.Condition queue 队列 生产者消费者模型 进程 Server process 进程池 协程 总结 线程 Threading用于提供线程相关的操作.线程是应用程序中工作的最小单元,它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. threading 模

  • Python进阶之协程详解

    目录 协程 协程的应用场景 抢占式调度的缺点 用户态协同调度的优势 协程的运行原理 Python 中的协程 总结 协程 协程(co-routine,又称微线程)是一种多方协同的工作方式.当前执行者在某个时刻主动让出(yield)控制流,并记住自身当前的状态,以便在控制流返回时能从上次让出的位置恢复(resume)执行. 简而言之,协程的核心思想就在于执行者对控制流的 “主动让出” 和 “恢复”.相对于,线程此类的 “抢占式调度” 而言,协程是一种 “协作式调度” 方式. 协程的应用场景 抢占式调

  • 实例详解Python的进程,线程和协程

    目录 前言 前提条件 相关介绍 实验环境 进程 多进程 用进程池对多进程进行操作 线程 使用_thread模块实现 使用threading模块实现 协程 使用asyncio模块实现 总结 前言 本文用Python实例阐述了一些关于进程.线程和协程的概念,由于水平有限,难免出现错漏,敬请批评改正. 前提条件 熟悉Python基本语法熟悉Python操作进程.线程.协程的相关库 相关介绍 Python是一种跨平台的计算机程序设计语言.是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言.最

  • python协程与 asyncio 库详情

    目录 1.asyncio 异步 I/O 库 异步函数的定义 事件循环 event_loop 创建 task 回调返回值 循环事件关闭 2.本节爬虫项目 前言: python 中协程概念是从 3.4 版本增加的,但 3.4 版本采用是生成器实现,为了将协程和生成器的使用场景进行区分,使语义更加明确,在 python 3.5 中增加了 async 和 await 关键字,用于定义原生协程. 1.asyncio 异步 I/O 库 python 中的 asyncio 库提供了管理事件.协程.任务和线程的

  • python 协程并发数控制

    目录 多线程之信号量 协程中使用信号量控制并发 aiohttp 中 TCPConnector 连接池 前言: 本篇博客要采集的站点:[看历史,通天下-历史剧网] 目标数据是该站点下的热门历史事件,列表页分页规则如下所示: http://www.lishiju.net/hotevents/p0 http://www.lishiju.net/hotevents/p1 http://www.lishiju.net/hotevents/p2 首先我们通过普通的多线程,对该数据进行采集,由于本文主要目的是

  • 一文搞懂​​​​​​​python可迭代对象,迭代器,生成器,协程

    目录 设计模式:迭代 python:可迭代对象和迭代器 为什么要有生成器? python的生成器实现 协程 设计模式:迭代 迭代是一种设计模式,解决有序便利序列的问题.通用的可迭代对象需要支持done和next方法. 伪代码如下: while not iterator.done(): item = iterator.next() ..... python:可迭代对象和迭代器 python的可迭代对象需要实现__iter__()方法,返回一个迭代器.for循环和顶级函数iter(obj)调用obj

  • Python获取协程返回值的四种方式详解

    目录 介绍 源码 依次执行结果 介绍 获取协程返回值的四种方式: 1.通过ensure_future获取,本质是future对象中的result方 2.使用loop自带的create_task, 获取返回值 3.使用callback, 一旦await地方的内容运行完,就会运行callback 4.使用partial这个模块向callback函数中传入值 源码 import asyncio from functools import partial async def talk(name): pr

  • Python协程实践分享

    目录 协程 yield在协程中的用法 经典示例 生产者-消费者模式(协程) gevent第三方库协程支持 经典代码 asyncio内置库协程支持 关于aiohttp 协程 协程简单来说就是一个更加轻量级的线程,并且不由操作系统内核管理,完全由程序所控制(在用户态执行).协程在子程序内部是可中断的,然后转而执行其他子程序,在适当的时候返回过来继续执行. 协程的优势?(协程拥有自己的寄存器上下文和栈,调度切换时,寄存器上下文和栈保存到其他地方,在切换回来的时候,恢复先前保存的寄存器上下文和栈,直接操

  • Python协程asyncio 异步编程笔记分享

    目录 1.事件循环 2.协程和异步编程 2.1 基本使用 2.2 await 2.3 Task对象 1.事件循环 可以理解成为一个死循环,去检查任务列表中的任务,如果可执行就去执行,如果检查不到就是不可执行的,那就忽略掉去执行其他可执行的任务,如果IO结束了(比如说去百度下载图片,下载完了就会变成可执行任务)再去执行下载完成之后的逻辑 #这里的任务是有状态的,比如这个任务已经完成或者正在执行或者正在IO等待 任务列表 = [ 任务1, 任务2, 任务3,... ] while True: 可执行

  • Python协程方式的实现及意义笔记分享

    目录 协程 1.greenlet实现协程 2.yield 3.asyncio 4.async & awit 2.协程的意义 小结 协程 协程不是计算机提供的,是程序员认为创造 协程也被称为微线程,是一种用户态的上下文切换技术,简而言之,就是通过一个线程实现代码互相切换执行 实现协程的几种方法: 1)greenlet,早期模块 2)yield关键字 3)asyncio装饰器 (python3.4以后引入的) 4)async,await关键字 (python3.5) 推荐 1.greenlet实现协

  • Python协程asyncio异步编程笔记分享

    目录 1.事件循环 2.协程和异步编程 2.1基本使用 2.2await 2.3Task对象 1.事件循环 可以理解成为一个死循环,去检查任务列表中的任务,如果可执行就去执行,如果检查不到就是不可执行的,那就忽略掉去执行其他可执行的任务,如果IO结束了(比如说去百度下载图片,下载完了就会变成可执行任务)再去执行下载完成之后的逻辑 #这里的任务是有状态的,比如这个任务已经完成或者正在执行或者正在IO等待 任务列表 = [ 任务1, 任务2, 任务3,... ] while True: 可执行的任务

  • python协程用法实例分析

    本文实例讲述了python协程用法.分享给大家供大家参考.具体如下: 把函数编写为一个任务,从而能处理发送给他的一系列输入,这种函数称为协程 def print_matchs(matchtext): print "looking for",matchtext while True: line = (yield) #用 yield语句并以表达式(yield)的形式创建协程 if matchtext in line: print line >>> matcher = pr

  • 浅析python协程相关概念

    这篇文章是读者朋友的python协程的学习经验之谈,以下是全部内容: 协程的历史说来话长,要从生成器开始讲起. 如果你看过我之前的文章python奇遇记:迭代器和生成器 ,对生成器的概念应该很了解.生成器节省内存,用的时候才生成结果. # 生成器表达式 a = (x*x for x in range(10)) # next生成值 next(a()) # 输出0 next(a()) # 输出1 next(a()) # 输出4 与生成器产出数据不同的是,协程在产出数据的同时还可以接收数据,具体来说就

  • Python协程操作之gevent(yield阻塞,greenlet),协程实现多任务(有规律的交替协作执行)用法详解

    本文实例讲述了Python 协程操作之gevent(yield阻塞,greenlet),协程实现多任务(有规律的交替协作执行)用法.分享给大家供大家参考,具体如下: 实现多任务:进程消耗的资源最大,线程消耗的资源次之,协程消耗的资源最少(单线程). gevent实现协程,gevent是通过阻塞代码(例如网络延迟等)来自动切换要执行的任务,所以在进行IO密集型程序时(例如爬虫),使用gevent可以提高效率(有效利用网络延迟的时间去执行其他任务). GIL(全局解释器锁)是C语言版本的Python

  • python 协程中的迭代器,生成器原理及应用实例详解

    本文实例讲述了python 协程中的迭代器,生成器原理及应用.分享给大家供大家参考,具体如下: 1.迭代器理解 迭代器: 迭代器是访问可迭代对象的工具 迭代器是指用iter(obj)函数返回的对象(实例) 迭代器是指用next(it)函数获取可迭代对象的数据 迭代器函数(iter和next) iter(iterable)从可迭代对象中返回一个迭代器,iterable必须是能提供一个迭代器的对象 next(iterator) 从迭代器iterator中获取下一了记录,如果无法获取下一条记录,则触发

  • Python协程 yield与协程greenlet简单用法示例

    本文实例讲述了Python协程 yield与协程greenlet简单用法.分享给大家供大家参考,具体如下: 协程 协程,又称微线程,纤程.英文名Coroutine. 协程是啥 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源). 为啥说它是一个执行单元,因为它自带CPU上下文.这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程. 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的. 通俗的理解:在一个线程中的某个函数,可以在任

  • python 协程 gevent原理与用法分析

    本文实例讲述了python 协程 gevent原理与用法.分享给大家供大家参考,具体如下: gevent greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent 其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络.文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行. 由于IO操

随机推荐