Python学习---协程 1226
协程【是一个单线程】,又称微线程,纤程。英文名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 = yield
print("[%s] is eating baozi %s" % (name, new_baozi))
# time.sleep(1)
def producer():
r = con.__next__()
r = con2.__next__()
n = 0
while n < 5:
n += 1
con.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
Python学习---协程 1226的更多相关文章
- python学习-----协程
一.协程的引入 对于单线程下,我们不可避免程序中出现io操作,但如果我们能在自己的程序中(即用户程序级别,而非操作系统级别)控制单线程下的多个任务能在一个任务遇到io阻塞时就切换到另外一个任务去计算, ...
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
本文参考:http://www.dabeaz.com/coroutines/ 作者:David Beazley 缘起: 本人最近在学习python的协程.偶然发现了David Beazley的co ...
- python gevent 协程
简介 没有切换开销.因为子程序切换不是线程切换,而是由程序自身控制,没有线程切换的开销,因此执行效率高, 不需要锁机制.因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断 ...
- 关于Python的协程问题总结
协程其实就是可以由程序自主控制的线程 在python里主要由yield 和yield from 控制,可以通过生成者消费者例子来理解协程 利用yield from 向生成器(协程)传送数据# 传统的生 ...
- {python之协程}一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二
python之协程 阅读目录 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本 ...
- 【Python】协程
协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在 ...
- Python之协程(coroutine)
Python之协程(coroutine) 标签(空格分隔): Python进阶 coroutine和generator的区别 generator是数据的产生者.即它pull data 通过 itera ...
- python的协程和_IO操作
协程Coroutine: 协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行. 注意,在一个子程序中中断,去执行其他子程序,不是函数调用,有点 ...
- python 3 协程函数
python 3 协程函数 1:把函数的执行结果封装好__iter__和__next__,即得到一个迭代器 2:与return功能类似,都可以返回值,但不同的是,return只能返回一次值,而yiel ...
随机推荐
- MySQL表级约束和列级约束
对一个数据列建立的约束,称为列级约束 对多个数据列建立的约束,称为表级约束 列级约束即可以在列定义时生命,也可以在列定义后声明. 表级约束只能在列定义后声明. NOT NULL和DEFAULT只存在列 ...
- 登陆界面背景动画的css样式
为了达到更好的用户体验,登陆界面需要设计多张背景图进行动态切换 <!doctype html> <html lang="en"> <head> ...
- CentOS 7下使用yum安装MySQL5.7
1.卸载 1.1先停掉mysql进程,没有安装过的可以直接跳过 pkill - mysqld rpm -qa|grep -i mysql 1.2用命令 yum -y remove -.el7.x86_ ...
- Golang教程:接口
什么是接口 在面向对象语言中,接口一般被定义为 :接口定义了一个对象的行为.它仅仅指定了一个对象应该做什么.具体怎么做(实现细节)是由对象决定的. 在 Go 中,一个接口定义为若干方法的签名.当一个类 ...
- Golang教程:并发介绍
Go是并发语言,而不是并行语言.在讨论Go并发性之前,我们必须首先了解什么是并发,以及并发与并行的区别. 什么是并发 并发(concurrency)是指一次处理大量事情的能力.让我们用一个例子来说明. ...
- Swift可选链
//可选链测试 class Person{ var residence:Residence! var name:String init(name:String){ self.name = name } ...
- MySql数据库与JDBC编程二
DML语法语句:主要操作数据表中的数据,完成插入新数据,修改已有数据,删除不要的数据的任务 1,insert into 语句 用于向指定表插入数据,一次只能插入一条记录:insert into tab ...
- HttpContext在多线程异步调用中的使用方案
1.在线程调用中,有时候会碰到操作文件之类的功能.对于开发人员来说,他们并不知道网站会被部署在服务器的那个角落里面,因此根本无法确定真实的物理路径(当然可以使用配置文件来配置物理路径),他们唯一知道的 ...
- spring整合struts2和hibernate
1.spring 1.1 jar包 1.2 spring.xml <?xml version="1.0" encoding="UTF-8"?> &l ...
- Spring学习笔记:jdbcTemplate和数据源配置
一.使用Spring框架jdbcTemplate实现数据库的增删改查 1.数据库 /* SQLyog Ultimate v8.32 MySQL - 5.7.19-log : Database - in ...