协程

协程是一种用户态的轻量级线程,又称微线程。

协程拥有自己的寄存器上下文和栈,调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

优点:

  1. 无需线程上下文切换的开销
  2. 无需原子操作锁定及同步的开销
  3. 方便切换控制流,简化编程模型
  4. 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。

原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。

缺点:

  1. 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  2. 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

使用Gevent

gevent是python的一个并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效.

  • 简单示例

gevent的sleep可以交出控制权,当我们在受限于网络或IO的函数中使用gevent,这些函数会被协作式的调度, gevent的真正能力会得到发挥。Gevent处理了所有的细节, 来保证你的网络库会在可能的时候,隐式交出greenlet上下文的执行权。

import gevent

def foo():
print('running in foo')
gevent.sleep(0)
print('com back from bar in to foo') def bar():
print('running in bar')
gevent.sleep(0)
print('com back from foo in to bar') # 创建线程并行执行程序
gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
])

  执行结果

running in foo
running in bar
com back from bar in to foo
com back from foo in to bar
  • 同步异步

import random
import gevent def task(pid):
gevent.sleep(random.randint(0, 2) * 0.001)
print('Task %s done' % pid) def synchronous():
for i in range(1, 10):
task(i) def asynchronous():
threads = [gevent.spawn(task, i) for i in range(10)]
gevent.joinall(threads) print('Synchronous:')
synchronous() print('Asynchronous:')
asynchronous()

  执行输出

Synchronous:
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 8 done
Task 9 done
Asynchronous:
Task 1 done
Task 4 done
Task 5 done
Task 9 done
Task 6 done
Task 0 done
Task 2 done
Task 3 done
Task 7 done
Task 8 done
  • 以子类的方法使用协程

可以子类化Greenlet类,重载它的_run方法,类似多线程和多进程模块

import gevent
from gevent import Greenlet class Test(Greenlet): def __init__(self, message, n):
Greenlet.__init__(self)
self.message = message
self.n = n def _run(self):
print(self.message, 'start')
gevent.sleep(self.n)
print(self.message, 'end') tests = [
Test("hello", 3),
Test("world", 2),
] for test in tests:
test.start() # 启动 for test in tests:
test.join() # 等待执行结束
  • 使用monkey patch修改系统标准库(自动切换协程)

当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。

由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成

import gevent
import requests
from gevent import monkey monkey.patch_socket() def task(url):
r = requests.get(url)
print('%s bytes received from %s' % (len(r.text), url)) gevent.joinall([
gevent.spawn(task, 'https://www.baidu.com/'),
gevent.spawn(task, 'https://www.qq.com/'),
gevent.spawn(task, 'https://www.jd.com/'),
])

  执行输出

2443 bytes received from https://www.baidu.com/
108315 bytes received from https://www.jd.com/
231873 bytes received from https://www.qq.com/

可以看出3个网络操作是并发执行的,而且结束顺序不同

参考链接:http://hhkbp2.github.io/gevent-tutorial/

python使用协程并发的更多相关文章

  1. Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)

    Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...

  2. python gevent 协程

    简介 没有切换开销.因为子程序切换不是线程切换,而是由程序自身控制,没有线程切换的开销,因此执行效率高, 不需要锁机制.因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断 ...

  3. 关于Python的协程问题总结

    协程其实就是可以由程序自主控制的线程 在python里主要由yield 和yield from 控制,可以通过生成者消费者例子来理解协程 利用yield from 向生成器(协程)传送数据# 传统的生 ...

  4. python3通过gevent.pool限制协程并发数量

    协程虽然是轻量级的线程,但到达一定数量后,仍然会造成服务器崩溃出错.最好的方法通过限制协程并发数量来解决此类问题. server代码: #!/usr/bin/env python # -*- codi ...

  5. {python之协程}一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二

    python之协程 阅读目录 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本 ...

  6. python之协程gevent模块

    Gevent官网文档地址:http://www.gevent.org/contents.html 进程.线程.协程区分 我们通常所说的协程Coroutine其实是corporate routine的缩 ...

  7. python的协程和_IO操作

    协程Coroutine: 协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行. 注意,在一个子程序中中断,去执行其他子程序,不是函数调用,有点 ...

  8. windows下多进程加协程并发模式

    好久没更新博客了.正好最近要整理一下最近这段时间做过的项目以及学习python的一些心得.如标题所示,今天就来说说windows下多进程加协程并发模式.其实网上还是蛮多在linux下的多进程加协程并发 ...

  9. 二、深入asyncio协程(任务对象,协程调用原理,协程并发)

      由于才开始写博客,之前都是写笔记自己看,所以可能会存在表述不清,过于啰嗦等各种各样的问题,有什么疑问或者批评欢迎在评论区留言. 如果你初次接触协程,请先阅读上一篇文章初识asyncio协程对asy ...

随机推荐

  1. js实现全屏和缩放

    /** * @description 简单的浏览器检查结果. * `webkit` * webkit版本号,如果浏览器为非webkit内核,此属性为`undefined`. * `chrome` * ...

  2. 【python-appium】Appium的一些坑问题错误解决 与 技巧集锦

    问题 1. error: Failed to start an Appium session, err was: Error: Requested a new session but one was ...

  3. opencl 参考源码及benchmark

    转载:https://www.zhihu.com/question/25539755/answer/44917891 CUDA 5之前的版本有OpenCL的sample,可以上网找找看 AMD APP ...

  4. 记一个centos分区大小调整过程

    1. 备份 /home 目录 [root@centos ~]# cp -r /home /home_backup 2. 查看目前磁盘使用的情况, 需要将 /dev/mapper/centos-home ...

  5. Android JNI 学习(九):Static Fields Api & Static Methods Api

    一.Accessing Static Fields(访问静态域) 1. GetStaticFieldID jfieldIDGetStaticFieldID(JNIEnv *env, jclass cl ...

  6. Kali学习笔记36:AVWS10的使用

    AVWS是一款商业Web扫描工具 适用于Windows操作系统 功能强大,必须掌握 AVWS11以上是Web形式,AVWS10是桌面应用形式 下载安装破解这些基本操作就不说了,百度即可 从安装好开始: ...

  7. [Postman]排除API请求(9)

    可能存在API无法运行或出现意外行为的情况.如果您没有收到任何回复,邮递员将显示有关连接服务器时出错的消息. 有关错误可能原因的更多详细信息,请打开Postman Console.它有关于故障的详细信 ...

  8. netty入门(一)

    1. netty入门(一) 1.1. 传统socket编程 在任何时候都可能有大量的线程处于休眠状态,只是等待输入或者输出数据就绪,这可能算是一种资源浪费. 需要为每个线程的调用栈都分配内存,其默认值 ...

  9. linux 使用 vim 玩python

    vim 的配置文件默认是当前用户宿主目录下的.vimrc 文件.下列配置是常用 vim 进行 python 开 发的配置. " 高亮当前行 set cursorline " 将 T ...

  10. 【Spark调优】聚合操作数据倾斜解决方案

    [使用场景] 对RDD执行reduceByKey等聚合类shuffle算子或者在Spark SQL中使用group by语句进行分组聚合时,经过sample或日志.界面定位,发生了数据倾斜. [解决方 ...