并发编程--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) 多线程几乎是每一个程序猿在使用每一种语言时都会首先想到用于解决并发的工具( ...
随机推荐
- js自增图片切换
使用js自增进行图片的切换 <!DOCTYPE html> <html lang="zh"> <head> <meta charset=& ...
- SpringBoot整合Redis(一)
docker启动redis docker run -p 6379:6379 --name myredis redis 查看容器 [root@topcheer ~]# docker ps -l CONT ...
- 死磕 java线程系列之线程池深入解析——定时任务执行流程
(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:本文基于ScheduledThreadPoolExecutor定时线程池类. 简介 前面我们一起学习了普通 ...
- 【xinsir】分享一个查找文件的脚手架
program.command('find <name>').action(name => { if (name) { inquirer .prompt([ { type: 'inp ...
- Elastic search集群新增节点(同一个集群,同一台物理机,基于ES 7.4)
一开始,在电脑上同一个集群新增节点(node)怎么试也不成功,官网guide又语焉不详?集群健康值yellow(表示主分片全部可用,部分复制分片不可用) 最后,在stackoverflow上找到了答案 ...
- 「2019.8.9 考试」神仙的dp总让人无所适从
T1是个容斥,我掐手指一算他为了卡容斥的正确性,绝不会把n和m出的很相近($O(n^2)$算法在nm相等的时候达到最高时间复杂度),不然就太好做了,于是开了特判+各种卡常和滚动数组优化,卡到了70分, ...
- drf
跨域同源 django做跨域同源 需要把csrf去掉 跨站请求伪造 同源 同源机制:域名.协议.端口号相同的同源 简单请求 不写头部请求 跨域会拦截报错缺少请求信息 (1) 请求方法是以下三种方法之一 ...
- Dubbo的应用
导语:Dubbo是阿里巴巴的一个分布式服务的开源框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000 ...
- PHP经典面试题:如何保证缓存与数据库的双写一致性?
只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 面试题剖析 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说 ...
- php如何在mysql里批量插入数据
假如说我有这样一个表,我想往这个表里面插入大量数据 CREATE TABLE IF NOT EXISTS `user_info` ( `id` int(11) NOT NULL AUTO_INCREM ...