不知道你有没有被问到过有没有使用过的python协程?

协程是什么?

协程是一种用户态轻量级,是实现并发编程的一种方式。说到并发,就能想到了多线程 / 多进程模型,是解决并发问题的经典模型之一。

但是随刻客户端数量达到一定量级,进程上下文切换占用了大量的资源,线程也顶不住如此巨大的压力,对于多线程应用,CPU通过切片的方式来切换线程间的执行,

线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。线程是抢占式的调度,而协程是协同式的调度,也就是说,协程需要自己做调度。

协程有什么用?

在别的语言中协程意义不大,多线程可解决问题,但是python因为他有GIL(Global Interpreter Lock 全局解释器锁 )在同一时间只有一个线程在工作,如果一个线程里面I/O操作特别多,协程就比较适用;

在python中多线程的执行情况如下图:

怎么实现协程?

python2.7中用生成器实现协程

在python3.7以后使用asyncio 和 async / await 的方法实现协程,实现过程就变得很简单

具体说明:简单的代码示例

import asyncio

import time

async def sub_function(str):

print(' {}'.format(str))

sleep_time = int(str.split('_')[-1])

await asyncio.sleep(sleep_time)

print('OK {}'.format(str))

async def main(strs):

for str in strs:

await sub_function(str)

# asyncio.run(main()) 作为主程序的入口函数,在程序运行周期内,只调用一次 asyncio.run

t0 = time.time()

asyncio.run(main(['str_1', 'str_2', 'str_3', 'str_4']))

t1 = time.time()

print("Total time running: %s seconds" %(str(t1 - t0)))

输出结果:一共是 10s 和我们顺序分析 分别等待 1 2 3 4 秒 好像没有什么提升作用,继续往下看

执行协程的方法有三种:

1. 入上例所示,用await 来调用实现,但是await 执行的效果,和 Python 正常执行是一样的,也就是说程序会阻塞在这里,进入被调用的协程函数,执行完毕返回后再继续,而这也是 await 的字面意思。

await 是同步调用,相当于我们用异步接口写了个同步代码,所以运行时间没有得到提升。

2. 上栗的异步想过没有体现出来,接下来我们使用另一个概念 task

async defsub_function(str):print('{}'.format(str))

sleep_time= int(str.split('_')[-1])

await asyncio.sleep(sleep_time)print('OK {}'.format(str))

asyncdefmain(strs):

#

tasks= [asyncio.create_task(sub_function(str)) for str instrs]for task intasks:

await task#asyncio.run(main()) 作为主程序的入口函数,在程序运行周期内,只调用一次 asyncio.run

t0 =time.time()

asyncio.run(main(['str_1', 'str_2', 'str_3', 'str_4']))

t1=time.time()print("Total time running: %s seconds" %(str(t1 - t0)))

们有了协程对象后,便可以通过 asyncio.create_task 来创建任务。任务创建后很快就会被调度执行,

这样,我们的代码也不会阻塞在任务这里。用for task in tasks: await task 即可。这次,你就看到效果了吧,结果显示,运行总时长等于运行时间最长一句。

运行结果:

3. 上面的task也可以用下面的方式写:

async defmain(strs):

tasks= [asyncio.create_task(sub_function(str)) for str instrs]

await asyncio.gather(*tasks)

唯一要注意的是,*tasks 解包列表,将列表变成了函数的参数;与之对应的是, ** dict 将字典变成了函数的参数。

在实际中,我们会遇到接口超时,我们就需要取消的情况,这种情况该怎么处理呢?再进一步,如果某些协程运行时出现错误,又该怎么处理呢?

importtimeimportasyncio

asyncdefworker_1():

await asyncio.sleep(1)return 1asyncdefworker_2():

await asyncio.sleep(2)return 2 /0

asyncdefworker_3():

await asyncio.sleep(3)return 3asyncdefmain():

task_1=asyncio.create_task(worker_1())

task_2=asyncio.create_task(worker_2())

task_3=asyncio.create_task(worker_3())

await asyncio.sleep(2)

task_3.cancel()

res= await asyncio.gather(task_1, task_2, task_3, return_exceptions=True)print(res)

t0=time.time()

asyncio.run(main())

t1=time.time()print("Total time running: %s seconds" %(str(t1 - t0)))

要注意return_exceptions=True这行代码。这个参数默认值为False, 如果不设置这个参数,错误就会完整地 throw 到我们这个执行层,从而需要 try except 来捕捉,

这也就意味着其他还没被执行的任务会被全部取消掉。为了避免这个局面,我们将 return_exceptions 设置为 True 即可。

线程能实现的,协程都能做到.

python协程实时输出_python协程相关推荐

  1. python从零开始到放弃_Python 协程从零开始到放弃

    0x00 前言 很久以前就听说 Python 的 async/await 很厉害,但是直到现在都没有用过,一直都在用多线程模型来解决各种问题.最近看到隔壁的 Go 又很火,所以决定花时间研究下 Pyt ...

  2. python 协程库_python --- 协程编程(第三方库gevent的使用)

    1. 什么是协程? 协程(coroutine),又称微线程.协程不是线程也不是进程,它的上下文关系切换不是由CPU控制,一个协程由当前任务切换到其他任务由当前任务来控制.一个线程可以包含多个协程,对于 ...

  3. python携程多核_python 协程

    最近对Python中的协程挺感兴趣,这里记录对协程的个人理解. 要理解协程,首先需要知道生成器是什么.生成器其实就是不断产出值的函数,只不过在函数中需要使用yield这一个关键词将值产出.下面来看一个 ...

  4. python 协程库_python协程概念

    什么是协程 协程是单线程下的并发,又称微线程,纤程.它是实现多任务的另一种方式,只不过是比线程更小的执行单元.因为它自带CPU的上下文,这样只要在合适的时机,我们可以把一个协程切换到另一个协程.英文名 ...

  5. python gevent模块 下载_Python协程阻塞IO非阻塞IO同步IO异步IO

    Python-协程-阻塞IO-非阻塞IO-同步IO-异步IO 一.协程 协程又称为微线程 CPU 是无法识别协程的,只能识别是线程,协程是由开发人员自己控制的.协程可以在单线程下实现并发的效果(实际计 ...

  6. python 协程原理_Python协程greenlet实现原理

    greenlet是stackless Python中剥离出来的一个项目,可以作为官方CPython的一个扩展来使用,从而支持Python协程.gevent正是基于greenlet实现. 协程实现原理 ...

  7. python 协程库_python 协程库gevent学习--gevent数据结构及实战(四)

    一不留神已经到第四部分了,这一部分继续总结数据结构和常用的gevent类,废话不多说继续. 1.Timeout错误类 晚上在调试调用第三方接口的时候,发现有些接口耗时非常多,觉得应该有个超时接口来限制 ...

  8. python 协程库_python 协程库gevent学习--源码学习(一)

    总算还是要来梳理一下这几天深入研究之后学习到的东西了. 这几天一直在看以前跟jd对接的项目写的那个gevent代码.为了查错,基本上深入浅出了一次gevent几个重要部件的实现和其工作的原理. 这里用 ...

  9. python主辅线程_python主线程捕获子线程的方法

    最近,在做一个项目时遇到的了一个问题,主线程无法捕获子线程中抛出的异常. 先看一个线程类的定义 ''''' Created on Oct 27, 2015 @author: wujz ''' impo ...

最新文章

  1. centos 7 安装tomcat
  2. 《PHP对象、模式与实践》之对象
  3. 解决报错ModuleNotFoundError: No module named ‘fastText‘
  4. Linux下Tomcat死活找不到JSP页面中import指定类的解决方法
  5. python安装opencv出错_python 3安装opencv 3时出错?
  6. python中基例_python | 自定义函数
  7. step1 基本语法流程控制
  8. Linux内核访问用户空间文件 filp_open/vfs_read/vfs_write/set_fs/get_fs
  9. Docker在千寻位置的实践
  10. Oracle组织架构
  11. android-x86编译
  12. Adobe Flash CS6 配置错误,错误代码:1
  13. 【Code】ASCII码表
  14. jenkins上展示html测试报告
  15. win10 蓝牙耳机配对成功,但无法连接
  16. Linux进程调度-CFS调度器原理分析及实现,懂了
  17. 响应式web mqtt应用
  18. 二分法求方程根--C语言
  19. 西北工业大学计算机学院人才特区,计算科学研究中心
  20. 山东大学计算机专业调剂信息,2020山东大学考研调剂信息

热门文章

  1. Scala操作外部数据
  2. 报错解决方法1:‘A GDAL API version must be specified.’
  3. 软件使用 excel
  4. Tableau实战系列Tableau基础概念全解析 (二)-万字长文解析数据类型及数据集
  5. MATLAB从入门到精通-MATLAB零矩阵zeros()函数使用方法汇总
  6. MATLAB实战系列(二十四)-MATLAB粒子群(PSO)优化算法在电力系统中的应用程序集合
  7. 机器学习中的数学(2)-线性回归,偏差、方差权衡
  8. Linuxubuntu chmod和chown命令用法详细介绍
  9. Matplotlib实例教程(一):柱状图(条形统计图)plt.bar()
  10. 【Linux】18_日志管理rsyslog系统日志管理