百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

协程在python中如何使用 协程 python3

lipiwang 2024-11-01 14:09 6 浏览 0 评论


什么是协程

协程,又称为微线程,纤程,英文名Coroutine。协程的作用是在执行函数A时,可以随时中断,去执行函数B,然后中断继续执行函数A(可以自由切换)。但这一过程并不是函数调用(没有调用语句),这一整个过程看似像多线程,然而协程只有一个线程执行。

优点

  • 执行效率极高,因为子程序切换(函数)不是线程切换,由程序自身控制,没有切换线程的开销。所有与多线程相比,线程的数量越多,协程性能的优势越明显。
  • 不需要多线程的锁机制,因为只有一个线程,也不存在同事写变量冲突,在控制共享资源时也不需要枷锁,因此执行效率高很多。

python 2.x的协程

主要应用:

yield和geventpython 2.x中支持协程的模块不多,常用的就是gevent。我们主要讲解gevent的用法。

Gevent

gevent是第三方库,通过greenlet实现协程,其基本思想:当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常好使,经常是程序处于等到状态,有了gevent为我们自动切换协程,就爆炸总有greenlet在运行,而不是等待IO。

gevent实现了python标准库里面大部分的阻塞式系统调用,包括socket、ssl、threading和select等模块,而将这些阻塞式调用变为协作式运行。通过monkey patch修改python自带的一些标准库。例子:

from gevent import monkey
monkey.patch_all() # 一定要在所有引入模块之前执行

import gevent
import reqeusts

def get_response(pn):
    print('start', pn)
    requests.get('https://www.baidu.com')
    print('end', pn)

tasks = [gevent.spawn(get_response, pn) for pn in range(5)]
gevent.joinall(tasks)

Gevent的方法:monkey使一些阻塞的模块变得不阻塞,遇到IO操作则自动切换

  • gevent.sleep 可以手动切换
  • gevent.spawn 启动协程,参数为(func_name,args)
  • gevent.joinall 阻塞当前流程,并执行所有给定的greenlet。执行流程只会在所有greenlet执行完后才会继续向下走

python 3.x的协程

python对协程的支持是通过生成器实现的。在生成器中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。但是python的yield不但可以返回一个值,它还可以接收调用者发出的参数。来看例子:

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None) #启动生成器,没有返回值
    n = 0
    while n < 5:
        n += 1
        print('Producing %s...' % n)
        r = c.send(n)
        print('Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

注意到consumer函数是一个生成器,把一个consumer传入produce后:

  • 调用c.send(None)启动生成器
  • 一旦生产了东西,通过c.send(n)切换到consumer执行
  • consumer通过yield拿到消息,处理,又通过yield把结果传回
  • produce拿到consumer处理的结果,继续生产下一条消息
  • produce决定不生产了,通过c.close()关闭consumer,整个过程结束
    整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。

上面只是协程的简单操作,python3中对协程的编程模型引入了一些标准库。python3.4以后引入了asyncio模块,可以很好的支持协程,asyncio的编程模型就是一个小小循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。

import asyncio

@asyncio.coroutine
def hello():
    print('Hello World!')
    # 异步调用asyncio.sleep(1)
    r = yield from asyncio.sleep(2)
    print('Hello again!')

# 获取EventLeep
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()

asyncio说明

  • @asyncio.coroutine把一个生成器标记为coroutine类型,然后我们就把这个coroutine扔到EventLoop中执行
  • hello()会首先答应出Hello World!然后yield from语法可以让我们方便的调用另一个生成器。由于asyncio.sleep也是一个coroutine,所以线程不会等待asyncio.sleep,而是直接中断并执行一个消息循环。当asyncio.sleep返回时,线程就可以从yield from拿到返回值(此处是None),然后接着执行下一行语句。
    把asyncio.sleep看成是一个好使1秒的IO操作,在此期间主线程并未等待,而是去执行EventLoop中其他可以执行的coroutine了,因此可以实现并发执行。

我们可以用Task封装两个coroutine试试:

import threading
import asyncio

@asyncio.coroutine
def hello():
    print('Hello World!(%s)' % threading.currentThread())
    yield from asyncio.sleep(1)
    print('Hello again! (%s)' % threading.currentThread())

loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

由打印的当前线程名称可以看出,两个coroutine是由同一个线程并发执行的。

为了简化并更好的标识异步IO,从python 3.5开始引入了新的语法async和await,可以让coroutine的代码更简洁易读。

请注意,async和await是针对coroutine的新语法,要使用新的语法,只需要做两部简单的替换:

把@asyncio.coroutine替换为async 把yield from替换为await
例如:

import asyncio

async def test(i):
    print('test_1', i)
    await asyncio.sleep(1)
    print('test_2', i)
loop = asyncio.get_event_loop()
tasks = [test(i) for i in range(5)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

相关推荐

ubuntu单机安装open-falcon极度详细操作

备注:以下操作均由本人实际操作并得到验证,喜欢的同学可尝试操作安装。步骤一1.1环境准备(使用系统:ubuntu18.04)1.1.1安装redisubuntu下安装(参考借鉴:https://...

Linux搭建promtail、loki、grafana轻量日志监控系统

一:简介日志监控告警系统,较为主流的是ELK(Elasticsearch、Logstash和Kibana核心套件构成),虽然优点是功能丰富,允许复杂的操作。但是,这些方案往往规模复杂,资源占用高,...

一文搞懂,WAF阻止恶意攻击的8种方法

WAF(Web应用程序防火墙)是应用程序和互联网流量之间的第一道防线,它监视和过滤Internet流量以阻止不良流量和恶意请求,WAF是确保Web服务的可用性和完整性的重要安全解决方案。它...

14配置appvolume(ios14.6配置文件)

使用AppVolumes应用程序功能,您可以管理应用程序的整个生命周期,包括打包、更新和停用应用程序。您还可以自定义应用程序分配,以向最终用户提供应用程序的特定版本14.1安装appvolume...

目前流行的缺陷管理工具(缺陷管理方式存在的优缺点)

摘自:https://blog.csdn.net/jasonteststudy/article/details/7090127?utm_medium=distribute.pc_relevant.no...

开源数字货币交易所开发学习笔记(2)——SpringCloud

前言码云(Gitee)上开源数字货币交易所源码CoinExchange的整体架构用了SpringCloud,对于经验丰富的Java程序员来说,可能很简单,但是对于我这种入门级程序员,还是有学习的必要的...

开发JAX-RPC Web Services for WebSphere(下)

在开发JAX-RPCWebServicesforWebSphere(上)一文中,小编为大家介绍了如何创建一个Web服务项目、如何创建一个服务类和Web服务,以及部署项目等内容。接下来小编将为大...

CXF学习笔记1(cxf client)

webservice是发布服务的简单并实用的一种技术了,个人学习了CXF这个框架,也比较简单,发布了一些笔记,希望对笔友收藏并有些作用哦1.什么是webServicewebService让一个程序可...

分布式RPC最全详解(图文全面总结)

分布式通信RPC是非常重要的分布式系统组件,大厂经常考察的Dubbo等RPC框架,下面我就全面来详解分布式通信RPC@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集》...

Oracle WebLogic远程命令执行0day漏洞(CVE-2019-2725补丁绕过)预警

概述近日,奇安信天眼与安服团队通过数据监控发现,野外出现OracleWebLogic远程命令执行漏洞最新利用代码,此攻击利用绕过了厂商今年4月底所发布的最新安全补丁(CVE-2019-2725)。由...

Spring IoC Container 原理解析(spring中ioc三种实现原理)

IoC、DI基础概念关于IoC和DI大家都不陌生,我们直接上martinfowler的原文,里面已经有DI的例子和spring的使用示例《InversionofControlContainer...

Arthas线上服务器问题排查(arthas部署)

1Arthas(阿尔萨斯)能为你做什么?这个类从哪个jar包加载的?为什么会报各种类相关的Exception?我改的代码为什么没有执行到?难道是我没commit?分支搞错了?遇到问题无法在...

工具篇之IDEA功能插件HTTP_CLENT(idea2021插件)

工具描述:Java开发人员通用的开发者工具IDEA集成了HTTPClient功能,之后可以无需单独安装使用PostMan用来模拟http请求。创建方式:1)简易模式Tools->HTTPCl...

RPC、Web Service等几种远程监控通信方式对比

几种远程监控通信方式的介绍一.RPCRPC使用C/S方式,采用http协议,发送请求到服务器,等待服务器返回结果。这个请求包括一个参数集和一个文本集,通常形成“classname.meth...

《github精选系列》——SpringBoot 全家桶

1简单总结1SpringBoot全家桶简介2项目简介3子项目列表4环境5运行6后续计划7问题反馈gitee地址:https://gitee.com/yidao620/springbo...

取消回复欢迎 发表评论: