多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[toc] ## 功能说明 gevent是greenlet模块的高级封装,greenlet可以实现根据用户自己的需要在单个线程的多个任务中进行任务切换,所以gevent封装了这个功能后,加入了对IO的判断,做到了在发现IO的情况下,自动切换任务的功能 所以我们先来了解greenlet模块的功能,后学习gevent的协程功能. * 安装greenlet :pip3 install greenlet * 安装gevent:pip3 install gevent ## greenlet模块 在单个线程内有多个任务,使用greenlet模块可以非常简单地实现任务直接的切换 但单纯的切换反而会降低程序的执行速度 ~~~ from greenlet import greenlet def eat(n): for i in range(3): print('%s is eat...%s'%(n,i)) g2.switch('noah') def play(n): for i in range(3): print('%s is paly...%s'%(n,i)) g1.switch() if __name__ == '__main__': g1=greenlet(eat) g2=greenlet(play) g1.switch('noah') #在第一次switch时传入参数,以后都不需要 ~~~ 执行结果: ``` noah is eat...0 noah is paly...0 noah is eat...1 noah is paly...1 noah is eat...2 noah is paly...2 ``` greenlet只是提供了一种便捷的切换方式,仍然是没有解决遇到IO自动切换来提升效率的问题。 ## gevent模块 gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是**Greenlet**, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。 **遇到IO阻塞时会自动切换任务** ### 用法 * g1=gevent.spawn(func,1,2,3,x=4,y=5) 创建一个协程对象g1,第一个参数是函数名,其他参数是位置实参或关键字实参 * g1.join() 等待g1对象结束 * gevent.joinall([g1,g2]) 等待多个协程对象介绍 * g1.value 拿到func1的返回值 ### 普通的用法案例1 ~~~ import gevent def eat(n): for i in range(3): print('%s is eat...%s'%(n,i)) gevent.sleep(0.5) def play(n): for i in range(3): print('%s is play...%s'%(n,i)) gevent.sleep(0.5) if __name__ == '__main__': g1=gevent.spawn(eat,'noah') g2=gevent.spawn(play,'bobo') gevent.joinall([g1,g2]) print('主...') # 执行结果: noah is eat...0 bobo is play...0 noah is eat...1 bobo is play...1 noah is eat...2 bobo is play...2 主... ~~~ >gevent.sleep(2)模拟的是gevent可以识别的io阻塞,其他模块如time模块中的io他是不能识别的 ### **打补丁和代码案例** 如果要让gevent识别所有的IO,就需要在文件的开头写上下面的代码(打补丁) `from gevent import monkey;monkey.patch_all()` **代码案例1:time模拟IO** ~~~ from gevent import monkey;monkey.patch_all() import gevent,time def eat(n): for i in range(3): print('%s is eat...%s'%(n,i)) time.sleep(0.5) def play(n): for i in range(3): print('%s is play...%s'%(n,i)) time.sleep(0.5) if __name__ == '__main__': g1=gevent.spawn(eat,'noah') g2=gevent.spawn(play,'bobo') gevent.joinall([g1,g2]) print('主...') #执行结果: noah is eat...0 bobo is play...0 noah is eat...1 bobo is play...1 noah is eat...2 bobo is play...2 主... ~~~ >用threading.current_thread().getName()来查看每个g1和g2 >查看的结果为**DummyThread-n**,即假线程 **代码案例2:协程socket并发** 这是服务端代码,客户端代码略 ~~~ from gevent import monkey;monkey.patch_all() import gevent,socket def ser(): server=socket.socket() server.bind(('127.0.0.1',8800)) server.listen() while True: conn,addr=server.accept() gevent.spawn(talk,conn,addr) def talk(conn,addr): try: while True: res=conn.recv(1024) if not res:continue print(res) conn.send(res.upper()) except Exception as e: print(e) if __name__ == '__main__': ser() ~~~