协程【是一个单线程】,又称微线程,纤程。英文名Coroutine。

一句话说明什么是协程:协程是一种用户态的轻量级线程【程序员自己去切换线程】

协程条件:

必须在只有一个单线程里实现并发

修改共享数据不需加锁

用户程序里自己保存多个控制流的上下文栈

一个协程遇到IO操作自动切换到其它协程

协程原理:

协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:

协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

协程的好处Nginx就是协程】:

无需线程上下文切换的开销【单线程

无需原子操作锁定及同步的开销

"原子操作(atomic operation)是不需要synchronized",所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。

方便切换控制流,简化编程模型

高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理

协程缺点:

无法利用多核资源【可以通过多进程实现多核利用】:协程的本质是个单线程,它不能同时将单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。

进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

最底层实际上使用yield实现协程操作

import time
import queue
def consumer(name):print("--->starting eating baozi...")while True:new_baozi = yieldprint("[%s] is eating baozi %s" % (name, new_baozi))# time.sleep(1)
def producer():r = con.__next__()r = con2.__next__()n = 0while n < 5:n += 1con.send(n)con2.send(n)print("\033[32;1m[producer]\033[0m is making baozi %s" % n)
if __name__ == '__main__':con = consumer("c1")con2 = consumer("c2")p = producer()

gevent

安装gevent

Gevent 介绍

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

import gevent
import time
def func1():print(time.ctime(), '\033[31;1mA-->B...\033[0m')gevent.sleep(2)   # 模拟IO阻塞print(time.ctime(), '\033[31;1mA-->B...\033[0m')
def func2():print(time.ctime(), '\033[32;1mB-->A...\033[0m')gevent.sleep(1)      # 模拟IO阻塞print(time.ctime(), '\033[32;1mB-->A...\033[0m')
# 一个线程自己切换,共耗时2秒,以最大的为准
gevent.joinall([gevent.spawn(func1),gevent.spawn(func2),
])

Greenlet

greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator

# -*- coding:utf-8 -*-
from greenlet import greenlet
def test1():print(12)gr2.switch()print(34)gr2.switch()
def test2():print(56)gr1.switch()print(78)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

协程爬虫

遇到IO阻塞时会自动切换任务[协程爬虫]

from gevent import monkey;
monkey.patch_all()   # 监听IO阻塞
import time
import gevent
from  urllib.request import urlopen
start = time.time()
def f(url, name):print('GET: %s' % url)resp = urlopen(url)data = resp.read()with open(name+'.thml', 'wb') as f:f.write(data)print('%d bytes received from %s.' % (len(data), url))
gevent.joinall([gevent.spawn(f, 'https://www.python.org/', 'python'),  # 就是这种格式传递参数gevent.spawn(f, 'https://www.yahoo.com/', 'yahoo'),gevent.spawn(f, 'https://github.com/', 'github'),
])
end = time.time()
print('gevent 耗时', str(end-start))

【更多参考】

http://www.cnblogs.com/alex3714/articles/5248247.html

转载于:https://www.cnblogs.com/ftl1012/p/9384297.html

Python学习---协程 1226相关推荐

  1. Python 的协程库 greenlet 和 gevent

    greenlet 官方文档:https://greenlet.readthedocs.io/en/latest/ From:https://www.jianshu.com/u/3ab212f28d91 ...

  2. python3 协程 写法_理解Python的协程(Coroutine)

    由于GIL的存在,导致Python多线程性能甚至比单线程更糟. GIL: 全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种 ...

  3. python携程使用_简单了解python gevent 协程使用及作用

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

  4. python 异步协程爬虫-半次元图片

    python 异步协程爬虫-半次元图片 1. 页面分析 2.代码大体构思 3.源码分析 3.1 完成效果 4.异步协程的优势 5.难点分析 6.可扩展性 欢迎私信或评论区交流 爬取网址 : https ...

  5. 理解Python的协程(Coroutine)

    生成器(Generator) yield表达式的使用 生产者和消费者模型 yield from表达式 协程(Coroutine) @asyncio.coroutine async/await 总结 参 ...

  6. python gevent 协程

    python gevent 协程 def func1():print("fun1开始运行")gevent.sleep(2) # 内部函数实现io操作print("func ...

  7. Python基础入门教程:使用 Python 3 协程快速获得一个代理池

    Python基础入门教程:使用 Python 3 协程快速获得一个代理池 前言 在执行 IO 密集型任务的时候,程序会因为等待 IO 而阻塞.比如我们使用 requests 库来进行网络爬虫请求的话, ...

  8. python中协程与函数的区别_深入浅析python 协程与go协程的区别

    进程.线程和协程 进程的定义: 进程,是计算机中已运行程序的实体.程序本身只是指令.数据及其组织形式的描述,进程才是程序的真正运行实例. 线程的定义: 操作系统能够进行运算调度的最小单位.它被包含在进 ...

  9. python中协程与函数的区别_python 协程与go协程的区别

    进程.线程和协程 进程的定义: 进程,是计算机中已运行程序的实体.程序本身只是指令.数据及其组织形式的描述,进程才是程序的真正运行实例. 线程的定义: 操作系统能够进行运算调度的最小单位.它被包含在进 ...

最新文章

  1. mitmdump脚本中使用requests模块发送请求
  2. 一直在构建工作空间_基于用户场景构建的建筑工程弱电设计工作设想
  3. linux x86板级文件,Linux driver 板级文件跟踪一般方法
  4. java 线程 Thread Runnable 实现样例
  5. python-函数的参数-位置参数-关键词参数
  6. 微信小程序的零食商城
  7. 树莓派 rfid_技术 | 对恶意树莓派设备的取证分析
  8. 一行一行分析JQ源码学习笔记-03
  9. 【Hadoop】HDFS三组件:NameNode、SecondaryNameNode和DataNode
  10. Docker系列(四)守护式容器
  11. 孙鑫VC学习笔记:第二讲 掌握C++
  12. 阿里云播放器组件 vue-aliplayer
  13. W3Cschool菜鸟教程离线版下载链接
  14. 算法分析与设计课程总结
  15. Windows javaw进程占用cpu资源100% 导致电脑卡顿
  16. Facebook的新算法可以预测出你的贫富阶级
  17. Ada的故事(转自互联网)
  18. 学会这招,小姐姐看你的眼神将不一样
  19. el-table设置表头样式,在table行间加入
  20. tampermonkey如何寻找_Tampermonkey脚本安装问题及自用脚本推荐

热门文章

  1. Delphi APP 開發入門(五)GPS 定位功能
  2. ping: sendto: Network is unreachable
  3. 灰盒测试—数据库软件
  4. 虚拟与现实的距离——VR的2016正如移动互联网的2009【下篇】
  5. GB2312、GBK与UTF-8的区别
  6. React Bind Handle的思考
  7. 子数组最大值设计02
  8. IT公司100题-4-在二元树中找出和为某一值的所有路径
  9. Tom's Classes
  10. Firefox 修改User Agent