iis服务器助手广告
返回顶部
首页 > 资讯 > 后端开发 > Python >如何理解Python中的协程
  • 382
分享到

如何理解Python中的协程

2023-06-16 05:06:11 382人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

这篇文章主要介绍“如何理解python中的协程”,在日常操作中,相信很多人在如何理解Python中的协程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Python中的协程”的疑惑有所帮助!接下来,请跟

这篇文章主要介绍“如何理解python中的协程”,在日常操作中,相信很多人在如何理解Python中的协程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Python中的协程”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

我们曾经在golang关于Goroutine的文章当中简单介绍过协程的概念,我们再来简单review一下。协程又称为是微线程,英文名是Coroutine。它和线程一样可以调度,但是不同的是线程的启动和调度需要通过操作系统来处理。并且线程的启动和销毁需要涉及一些操作系统的变量申请和销毁处理,需要的时间比较长。而协程呢,它的调度和销毁都是程序自己来控制的,因此它更加轻量级也更加灵活。

协程有这么多优点,自然也会有一些缺点,其中最大的缺点就是需要编程语言自己支持,否则的话需要开发者自己通过一些方法来实现协程。对于大部分语言来说,都不支持这一机制。go语言由于天然支持协程,并且支持得非常好,使得它广受好评,短短几年时间就迅速流行起来。

对于Python来说,本身就有着一个GIL这个巨大的先天问题。GIL是Python的全局,在它的限制下一个Python进程同一时间只能同时执行一个线程,即使是在多核心的机器当中。这就大大影响了Python的性能,尤其是在CPU密集型的工作上。所以为了提升Python的性能,很多开发者想出了使用多进程+协程的方式。一开始是开发者自行实现的,后来在python3.4的版本当中,官方也收入了这个功能,因此目前可以光明正大地说,Python是支持协程的语言了。

生成器(generator)

生成器我们也在之前的文章当中介绍过,为什么我们介绍协程需要用到生成器呢,是因为Python的协程底层就是通过生成器来实现的。

通过生成器来实现协程的原因也很简单,我们都知道协程需要切换挂起,而生成器当中有一个yield关键字,刚好可以实现这个功能。所以当初那些自己在Python当中开发协程功能的程序员都是通过生成器来实现的,我们想要理解Python当中协程的运用,就必须从最原始的生成器开始。

生成器我们很熟悉了,本质上就是带有yield这个关键词的函数。

def test():     n = 0     while n < 10:         val = yield n          print('val = {}'.fORMat(val))         n += 1

这个函数当中如果没有yield这个语句,那么它就是一个普通的Python函数。加上了val = yield n这个语句之后,它有什么变化呢?

我们尝试着运行一下:

# 调用test函数获得一个生成器 g = test() print(next(g)) print(next(g)) print(next(g))

得到这么一个结果:

如何理解Python中的协程

输出的0,1,2很好理解,就是通过next(g)返回的,这个也是生成器的标准用法。奇怪的是为什么val=None呢?val不应该等于n么?

这里想不明白是正常的,因为这里涉及到了一个新的用法就是生成器的send方法。当我们在yield语句之前加上变量名的时候,它的含义其实是返回yield之后的内容,再从外界接收一个变量。也就是说当我们执行next(g)的时候,会从获取yield之后的数,当我们执行g.send()时,传入的值会被赋值给yield之前的数。比如我们把执行的代码改成这样:

g = test() print(next(g)) g.send('abc') print(next(g)) print(next(g))

我们再来看执行的结果,会发现是这样的:

如何理解Python中的协程

第一行val不再是None,而是我们刚刚传入的abc了。

队列调度

生成器每次在执行到yield语句之后都会自然挂起,我们可以利用这一点来当做协程来调度。我们可以自己实现一个简易的队列来模拟这个过程。

首先我们声明一个双端队列,每次从队列左边头部获取任务,调度执行到挂起之后,放入到队列末尾。相当于我们用循环的方式轮询执行了所有任务,并且这整个全程不涉及任何线程创建和销毁的过程。

class Scheduler:     def __init__(self):         self._queue = deque()      def new_task(self, task):         self._queue.append(task)      def run(self):         while self._queue:             # 每次从队列左侧获取task             task = self._queue.popleft()             try:                 # 通过next执行之后放入队列右侧                 next(task)                 self._queue.append(task)             except StopIteration:                 pass    sch = Scheduler() sch.new_task(test(5)) sch.new_task(test(10)) sch.new_task(test(8)) sch.run()

这个只是一个很简易的调度方法,事实上结合上yield  from以及send功能,我们还可以实现出更加复杂的协程调度方式。但是我们也没有必要一一穷尽,只需要理解最基础的方法就可以了,毕竟现在我们使用协程一般也不会自己实现了,都会通过官方原生的工具库来实现。

@asyncio.coroutine

在Python3.4之后的版本当中,我们可以通过@asyncio.coroutine这个注解来将一个函数封装成协程执行的生成器。

在吸收了协程这个概念之后,Python对生成器以及协程做了区分。加上了@asyncio.coroutine注解的函数称为协程函数,我们可以用iscoroutinefunction()方法来判断一个函数是不是协程函数,通过这个协程函数返回的生成器对象称为协程对象,我们可以通过iscoroutine方法来判断一个对象是不是协程对象。

比如我把刚刚写的函数上加上注解之后再来执行这两个函数都会得到True:

import asyncio  @asyncio.coroutine def test(k):     n = 0     while n < k:         yield         print('n = {}'.format(n))         n += 1          print(asyncio.iscoroutinefunction(test)) print(asyncio.iscoroutine(test(10)))

那我们通过注解将方法转变成了协程之后,又该怎么使用呢?

一个比较好的方式是通过asyNIO库当中提供的loop工具,比如我们来看这么一个例子:

loop = asyncio.get_event_loop() loop.run_until_complete(test(10)) loop.close()

我们通过asyncio.get_event_loop函数创建了一个调度器,通过调度器的run相关的方法来执行一个协程对象。我们可以run_until_complete也可以run_forever,具体怎么执行要看我们实际的使用场景。

async,await和future

从Python3.5版本开始,引入了async,await和future。我们来简单说说它们各自的用途,其中async其实就是@asyncio.coroutine,用途是完全一样的。同样await代替的是yield  from,意为等待另外一个协程结束。

我们用这两个一改,上面的代码就成了:

async def test(k):     n = 0     while n < k:         await asyncio.sleep(0.5)         print('n = {}'.format(n))         n += 1

由于我们加上了await,所以每次在打印之前都会等待0.5秒。我们把await换成yield  from也是一样的,只不过用await更加直观也更加贴合协程的含义。

Future其实可以看成是一个信号量,我们创建一个全局的future,当一个协程执行完成之后,将结果存入这个future当中。其他的协程可以await  future来实现阻塞。我们来看一个例子就明白了:

future = asyncio.Future()  async def test(k):     n = 0     while n < k:         await asyncio.sleep(0.5)         print('n = {}'.format(n))         n += 1     future.set_result('success')  async def log():     result = await future     print(result)   loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait([     log(),     test(5) ]))  loop.close()

在这个例子当中我们创建了两个协程,第一个协程是每隔0.5秒print一个数字,在print完成之后把success写入到future当中。第二个协程就是等待future当中的数据,之后print出来。

在loop当中我们要调度执行的不在是一个协程对象了而是两个,所以我们用asyncio当中的wait将这两个对象包起来。只有当wait当中的两个对象执行结束,wait才会结束。loop等待的是wait的结束,而wait等待的是传入其中的协程的结束,这就形成了一个依赖循环,等价于这两个协程对象结束,loop才会结束。

到此,关于“如何理解Python中的协程”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 如何理解Python中的协程

本文链接: https://www.lsjlt.com/news/282539.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何理解Python中的协程
    这篇文章主要介绍“如何理解Python中的协程”,在日常操作中,相信很多人在如何理解Python中的协程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Python中的协程”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-16
  • 如何理解Python进程、线程、协程
    本篇内容介绍了“如何理解Python进程、线程、协程”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!什么是进...
    99+
    2024-04-02
  • 如何理解JS中的Generator及协程
    这篇文章主要讲解了“如何理解JS中的Generator及协程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解JS中的Generator及协程”吧!生成...
    99+
    2024-04-02
  • 如何理解WEB开发中的Python WSGI协议
    今天就跟大家聊聊有关如何理解WEB开发中的Python WSGI协议,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Web应用程序开发Web应用程序的本质是什么简单描述Web应用程序的...
    99+
    2023-06-02
  • 如何理解Swift中的协议
    本篇内容主要讲解“如何理解Swift中的协议”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解Swift中的协议”吧!1. 前言协议定义了一个蓝图,规定了用...
    99+
    2024-04-02
  • Python中TCP协议的理解
    Test01–>TCP客户端案例 #! /usr/bin/env python3 # -*- coding:utf-8 -*- from socket import * def main(): # 1.创...
    99+
    2023-01-31
    协议 Python TCP
  • Python协程一点理解
    def test(): for i in 'abc': yield i for i in [1, 2, 3]: yield i if __name__ == '__main__': ...
    99+
    2023-01-31
    Python
  • 如何在 Golang 中协调协程?
    非常抱歉,由于您没有提供文章标题,我无法为您生成一篇高质量的文章。请您提供文章标题,我将尽快为您生成一篇优质的文章。...
    99+
    2024-05-21
  • 如何理解HTTP协议中的状态码
    这篇文章主要介绍“如何理解HTTP协议中的状态码”,在日常操作中,相信很多人在如何理解HTTP协议中的状态码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解HTTP协议中的状态码”的疑惑有所帮助!接下来...
    99+
    2023-06-08
  • Android中的Coroutine协程原理解析
    前言 协程是一个并发方案。也是一种思想。 传统意义上的协程是单线程的,面对io密集型任务他的内存消耗更少,进而效率高。但是面对计算密集型的任务不如多线程并行运算效率高。 不同的语言...
    99+
    2024-04-02
  • 理解Golang中线程与协程的工作原理
    Golang中线程与协程的工作原理 在Go语言(Golang)中,线程和协程是非常重要的概念,它们是并发编程的基本组成部分。理解它们的工作原理对于开发高效的并发程序非常重要。本文将深入...
    99+
    2024-02-29
    golang 线程 协程 go语言 并发访问
  • 如何使用Python中的协程进行异步编程
    如何使用Python中的协程进行异步编程在传统的同步编程模型中,一个任务必须等待另一个任务完成后才能继续进行,这样会造成程序的执行效率降低。为了解决这个问题,异步编程模型应运而生。Python中的协程是一种支持异步编程的重要概念,它可以让我...
    99+
    2023-10-28
    Python 协程 异步编程
  • Python线程编程中的Thread该如何理解
    Python线程编程中的Thread该如何理解,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、线程编程(Thread)1、线程基本概念1.1、什么事线程线程被称为轻量级的...
    99+
    2023-06-22
  • python协程与golang协程的区
    进程、线程和协程 进程的定义: 进程,是计算机中已运行程序的实体。程序本身只是指令、数据及其组织形式的描述,进程才是程序的真正运行实例。 线程的定义: 操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。 进程...
    99+
    2023-01-31
    python golang
  • 如何在python中使用await协程函数
    如何在python中使用await协程函数?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。python主要应用领域有哪些1、云计算,典型应用OpenStack。2、WEB前端开发...
    99+
    2023-06-14
  • python 中的 asyncio 异步协程
    目录一、定义协程二、运行协程三、协程回调四、运行多个协程五、run_forever六、多协程中关闭run_forever一、定义协程 asyncio 执行的任务,称为协程,但是Asy...
    99+
    2024-04-02
  • 如何理解TypeScript中的子类型、逆变、协变
    这篇文章主要介绍“如何理解TypeScript中的子类型、逆变、协变”,在日常操作中,相信很多人在如何理解TypeScript中的子类型、逆变、协变问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方...
    99+
    2024-04-02
  • python中Task封装协程的知识点梳理
    本篇内容主要讲解“python中Task封装协程的知识点梳理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python中Task封装协程的知识点梳理”吧!说明Task是Future的子类,Tas...
    99+
    2023-06-20
  • Python 协程与 JavaScript 协程的对比
    目录1、前言2、什么是协程?3、混乱的历史3.1Python协程的进化4、JavaScript协程的进化5、Python协程成熟体5.1协程(coroutine)5.2任务(Task...
    99+
    2024-04-02
  • 如何快速掌握Python协程
    这篇文章主要讲解了“如何快速掌握Python协程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何快速掌握Python协程”吧! 1. 协程相关的概念1.1 进程和线程进程(Pro...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作