并发编程--greenlet与gevent
什么是greenlet?
虽然CPython(标准Python)能够通过生成器来实现协程,但使用起来还并不是很方便。
与此同时,Python的一个衍生版 Stackless Python实现了原生的协程,它更利于使用。
于是,大家开始将 Stackless 中关于协程的代码单独拿出来做成了CPython的扩展包。
这就是 greenlet 的由来,因此 greenlet 是底层实现了原生协程的 C扩展库
greenlet的基本使用
# 基于greenlet的生产者消费者协程
from greenlet import greenlet
import random
import time def Producer():
while True:
item = random.randint(1, 10)
print("生产<{}>中...".format(item))
time.sleep(1)
c.switch(item) # 切换到消费者,并将item传入。 def Consumer():
while True:
item = p.switch() # 切换到生产者。等待生产者传递参数item
print("消费<{}>中..".format(item)) c = greenlet(Consumer) # 将普通函数编程协程
p = greenlet(Producer) # 同理
c.switch() # 启动协程,Consumer先执行
"""
从consumer开始执行,执行到item=p.switch()时,程序切换到producer,并等待传参
producer得到执行权后,生成一个item,并往下执行代码
当producer执行到c.switch(item)时,程序携带传递的item切换到consumer,
consumer继续往下执行,直到下一次运行到p.switch时,交出执行权,切换到producer,重复以上过程 greenlet的价值在于高性能的原生协程,
且语义更加明确、显示切换
执行到switch时就切换程序
直接将函数包装成协程,可以保留原代码的风格
"""
什么是gevent?
虽然,我们有了 基于 epoll 的回调式编程模式,但是却难以使用。即使我们可以通过配合 生成器协程 进行复杂的封装,以简化编程难度。
但是仍然有一个大的问题: 封装难度大,现有代码几乎完全要重写gevent,通过封装了 libev(基于epoll) 和 greenlet 两个库。
帮我们做好封装,允许我们以类似于线程的方式使用协程。以至于我们几乎不用重写原来的代码就能充分利用 epoll 和 协程 威力。
gevent的常用操作
"""
gevent: 通过greenlet实现协程,核心就是遇到IO操作,会自动切换到其他协程 """
# 将python标准库中的一些阻塞操作变为非阻塞
from gevent import monkey;monkey.patch_all()
# 使用猴子补丁要写在第一行
import gevent def test1():
print("test1")
gevent.sleep(0) # 模拟耗时操作
print("test11") def test2():
print("test2")
gevent.sleep(0) # 模拟耗时操作
print("test22") # g1 = gevent.spawn(test1) # 将函数封装成协程,并启动
# g2 = gevent.spawn(test2)
# gevent.joinall([g1, g2]) """
# joinall() 阻塞当前流程,执行给定的greenlet(列表中的对象),等待程序执行完
# spawn是启动协程,参数为函数名及其参数 运行结果:
test1
test2
test11
test22 代码执行test1,打印test1,遇到gevent.sleep(0)时切换程序,执行test2
test()执行,打印test2,执行到gevent.sleep(0)时切换程序
执行test1在gevent.sleep(0)后面的代码,直到再次遇到gevent时,切换程序
然后在test2中,继续执行gevent后的代码,直到遇到gevent时,再次切换
直到程序执行完毕 gevent的价值在于它的使用基于epoll的libev来避开阻塞;
使用基于gevent的高效协程,来切换执行
只在遇到阻塞的时候切换,没有轮询和线程开销
"""
基于gevent的并发服务器
# 基于gevent的并发服务器实现
import gevent
# 将python内置的socket换成封装了IO多路复用的socket
from gevent import monkey;monkey.patch_all()
import socket # 实例化socket
server = socket.socket()
# 绑定ip和端口
server.bind(('0.0.0.0', 8000))
# 绑定监听数量
server.listen(1000) def worker(connection):
"""
协程需要处理的事情
:param connection:
:return:
"""
while True:
recv_data = connection.recv(1024) # 等待接收数据
if recv_data:
print(recv_data)
connection.send(recv_data) # 将接收的数据原路返回
else:
connection.close() # 发送完毕断开
break while True:
conn, addr = server.accept() # 等待客户端连接,遇到阻塞切换
gevent.spawn(worker, conn) # 生成协程,并将conn作为参数传入
gevent的通信
# gevent通信
import time
import random from gevent import monkey;monkey.patch_all()
import gevent
from gevent.queue import Queue def write(q):
while True:
print("put:{}".format('text'))
q.put('text')
gevent.sleep(0) # 模拟阻塞 def read(q):
while True:
print("get:{}".format(q.get())) # get本身是阻塞 # q = Queue()
# w = gevent.spawn(write, q) # 遇到阻塞自动切换
# r = gevent.spawn(read, q)
# gevent.joinall([w, r])
并发编程--greenlet与gevent的更多相关文章
- python 并发编程 协程 gevent模块
一 gevent模块 gevent应用场景: 单线程下,多个任务,io密集型程序 安装 pip3 install gevent Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步 ...
- 并发编程协程(Coroutine)之Gevent
并发编程协程之Gevent Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate r ...
- python 并发编程 协程 目录
python 并发编程 协程 协程介绍 python 并发编程 协程 greenlet模块 python 并发编程 协程 gevent模块 python 并发编程 基于gevent模块实现并发的套接字 ...
- 14 并发编程-(协程)-greenlet模块&gevent模块
1.实现多个任务之间进行切换,yield.greenlet都没有实现检测I/O,greenlet在实现多任务切换下更简单 from greenlet import greenlet def eat(n ...
- Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)
Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...
- Python自动化之select、greenlet和gevent和事件驱动模型初探
进程.线程和协程的区别 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度. 线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的). 协程和线程一样 ...
- python系列之 - 并发编程(进程池,线程池,协程)
需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...
- day22-多并发编程基础(三)
今天学习了并发编程中的最后一部分,协程,也是python中区别于java,c等语言中很大不同的一部分 1.协程产生的背景 2.协程的概念 3.yield模拟协程 4.协程中主要的俩个模块 5.协程的应 ...
- 使用Python进行并发编程
让计算机程序并发的运行是一个经常被讨论的话题,今天我想讨论一下Python下的各种并发方式. 并发方式 线程(Thread) 多线程几乎是每一个程序猿在使用每一种语言时都会首先想到用于解决并发的工具( ...
随机推荐
- reduce,map,filter 的用法
# filter用法 (对每一个数据进行筛选,满足条件的就保留)# 1,filter(功能函数,容器类型数据)# 2,过滤出来是一个地址,用list,或tuple进行包装# 3,过滤出来的是原容器类型 ...
- Flask:Flask中使用会话技术
1.会话技术cookie和session (1)cookie 在网站中,HTTP请求是无状态的.也就是说,即使第一次用户访问服务器并登录成功后,第二次请求服务器依然不知道当前发起请求的是哪个用户.co ...
- Java 干货之深入理解Java内部类
可以将一个类定义在另一个类或方法中,这样的类叫做内部类 --<Thinking in Java> 说起内部类,大家并不陌生,并且会经常在实例化容器的时候使用到它.但是内部类的具体细节语法, ...
- [2018-07-19] 安装python
1.Python官网 https://www.python.org/downloads/ 2.应该使用Python2.x还是Python3.x? Python有2.x和3.x两个版本,这两个版本是不兼 ...
- 在线热备份数据库之innobackupex 增量备份InnoDB
在线热备份数据库之innobackupex 增量备份InnoDB 什么是增量备份?其原理是什么? 增量备份是基于上一次备份后对新增加的内容进行备份,优点相较于完整备份而言备份内容少时间短,能够节省磁盘 ...
- csps模拟测试110
好久没写博客了,主要是太懒了,这次考试其实状态还算好. 考试的时候半小时左右打完T1T2,先没打T2对拍,想了想T3,大概有了一个bitset的思路,回去补上了T2的对拍. 然后T3想了一些东西: 三 ...
- 使用Typescript重构axios(五)——实现基础功能:处理请求的header
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(二十九)——添加baseURL
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- P2934 [USACO09JAN]安全出行
图论瞎搞...... solution: 按例化简:给定一个无向图,保证单源最短路唯一,求每个点到1号点的最短路最后一条边被封锁的情况下的最短路 乍一看,应该是次短路,但是稍微用脚趾头想想都能发现不是 ...
- echarts动态刷新数据
在这次的项目中图表显示的部分比较多,这边给分享下用到的图表的数据刷新 饼图最后的效果 先看下 前端部分 <div div style="height: 40%; width: 17.5 ...