Python--协程(gevent模块)

一:前言

协程又称为微线程,纤程。英文名Coroutine:协程是一种用户态的轻量级线程

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

协程能够保留上次一调用时的状态,能够进入上一次离开时所处的逻辑流的位置

协程的好处

无需线程上下文切换的开销
无需原子操作(不会被线程调度机制打断的操作)锁定以及同步的开销
方便切换控制流,简化编程模型
高并发+高扩展性+低成文:一个CPU支持上完的协程都不是问题,所以很适合高并发处理

协程的缺点

无法利用多核资源:协程的本质是单线程,需要和进程配合才能运行在多CPU上
进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

协程的条件

必须在只有一个单线程里实现并发
修改共享数据不需加锁
用户程序里自己保存多个控制流的上下文栈
一个协程遇到IO操作自动切换到其它协程

使用yield实现协程

def consumer(name):print("--->starting eating baozi...")while True:new_baozi = yieldprint("[%s] is eating baozi %s" % (name, new_baozi))def producer():next(con)next(con2)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()

二:Greenlet

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

使用greenlet实现协程

    from greenlet import greenletdef f1():print(12)gr2.switch()print(34)gr2.switch()def f2():print(56)gr1.switch()print(78)if __name__=='__main__':gr1 = greenlet(f1)gr2 = greenlet(f2)gr1.switch()     #手动切换,gevent是对greenlet的封装,实现自动切换

运行结果:

12
56
34
78

三:Gevent

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

使用gevent库实现协程

    import geventdef func1():print("func1 running")gevent.sleep(2)             # 内部函数实现io操作print("switch func1")def func2():print("func2 running")gevent.sleep(1)print("switch func2")def func3():print("func3  running")gevent.sleep(0.5)print("func3 done..")if __name__=='__main__':gevent.joinall([gevent.spawn(func1),gevent.spawn(func2),gevent.spawn(func3),])

运行结果:

func1 running
func2 running
func3  running
func3 done..
switch func2
switch func1

同步与异步的性能区别

    import geventdef task(pid):"""Some non-deterministic task"""gevent.sleep(0.5)print('Task %s done' % pid)def synchronous():for i in range(1, 10):task(i)def asynchronous():threads = [gevent.spawn(task, i) for i in range(10)]gevent.joinall(threads)if __name__ =='__main__':print('Synchronous:')synchronous()print('Asynchronous:')asynchronous()

运行结果:

Synchronous:
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 8 done
Task 9 done
Asynchronous:
Task 0 done
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 8 done
Task 9 done

将task函数封装到Greenlet内部线程的gevent.spawn。 初始化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall 函数,后者阻塞当前流程,并执行所有给定的greenlet。执行流程只会在 所有greenlet执行完后才会继续向下走。

遇到IO阻塞时会自动切换任务

from gevent import monkeymonkey.patch_all()
import gevent
from  urllib.request import urlopendef f(url):print('GET: %s' % url)resp = urlopen(url)data = resp.read()print('%d bytes received from %s.' % (len(data), url))if __name__=='__main__':gevent.joinall([gevent.spawn(f, 'https://www.python.org/'),gevent.spawn(f, 'https://www.yahoo.com/'),gevent.spawn(f, 'https://github.com/'),])

通过gevent实现单线程下的多socket并发

server端

import sys
import socket
import time
import geventfrom gevent import socket,monkey
monkey.patch_all()def server(port):s = socket.socket()s.bind(('0.0.0.0', port))s.listen(500)while True:cli, addr = s.accept()gevent.spawn(handle_request, cli)def handle_request(conn):try:while True:data = conn.recv(1024)print("recv:", data)conn.send(data)if not data:conn.shutdown(socket.SHUT_WR)except Exception as  ex:print(ex)finally:conn.close()
if __name__ == '__main__':server(8001)

client 端

import socketHOST = 'localhost'    # The remote host
PORT = 8001           # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:msg = bytes(input(">>:"),encoding="utf8")s.sendall(msg)data = s.recv(1024)#print(data)print('Received', repr(data))
s.close()

并发100socket连接

import socket
import threadingdef sock_conn():client = socket.socket()client.connect(("localhost",8001))count = 0while True:#msg = input(">>:").strip()#if len(msg) == 0:continueclient.send( ("hello %s" %count).encode("utf-8"))data = client.recv(1024)print("[%s]recv from server:" % threading.get_ident(),data.decode()) #结果count +=1client.close()for i in range(100):t = threading.Thread(target=sock_conn)t.start()

原文链接:https://blog.csdn.net/qq_39112646/article/details/86776107
感谢作者分享!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ffmpeg 0.6.3 代码, 经过我努力,能够在vs 2005 下单步调试代码

1. ffmpeg-0.6.3_modify.7z 是修改后的ffmepg的代码&#xff1b; 2.ffmpeg-0.6.3_srouce.tar.bz2 是ffmpeg原始代码&#xff1b; 3.SDL-devel-1.2.15-VC.zip 是图像显示使用使用的sdl代码&#xff1b; 4.w_cc_p_10.1.020.exe 是vc 2005 需要使用的编译器&#xff1b…

克隆CentOS6虚拟机eth0被修改为eth1如何修改eth0

2019独角兽企业重金招聘Python工程师标准>>> 直接修改 /etc/sysconfig/network-script/ifcfg-eth0 删掉UUID HWADDR 配置静态地址 然后&#xff1a; rm -rf  /etc/udev/rules.d/70-persistent-net.rules然后reboot 转载于:https://my.oschina.net/hengbao666/blog/…

[Hnoi2013]消毒

Description 最近在生物实验室工作的小T遇到了大麻烦。 由于实验室最近升级的缘故&#xff0c;他的分格实验皿是一个长方体,其尺寸为abc&#xff0c;a、b、c 均为正整数。为了实验的方便&#xff0c;它被划分为abc个单位立方体区域&#xff0c;每个单位立方体尺寸 为111。用(i,…

php按照文件名字排序,php readdir 排序问题,如何按照日期进行排序

目前是这么写的&#xff1a;function posts_get($directory,$ext){if (is_dir($directory)) {$handle opendir($directory);while ($file readdir($handle)){$subdir $directory . / .$file;if ($file ! . && $file !.. && is_dir($subdir)){posts_get($sub…

关系模型的名词

关系&#xff08;Relation&#xff09;一个关系对应通常说的一张表元组&#xff08;Tuple&#xff09;表中的一行即为一个元组属性&#xff08;Attribute&#xff09;表中的一列即为一个属性&#xff0c;给每一个属性起一个名称即属性名主码&#xff08;Key&#xff09;也称码键…

物理卷、卷组、逻辑卷

参考文章&#xff1a; 相关文献 谢谢作者分享!

fibonacci数列的题目——剑指Offer

https://www.nowcoder.net/practice/c6c7742f5ba7442aada113136ddea0c3?tpId13&tqId11160&tPage1&rp1&ru/ta/coding-interviews&qru/ta/coding-interviews/question-ranking 大家都知道斐波那契数列&#xff0c;现在要求输入一个整数n&#xff0c;请你输出…

如何高效的编写与同步博客 (.NET Core 小工具实现)

系列目录 [如何高效的编写与同步博客&#xff08;一&#xff09;- 编写 ]如何高效的编写与同步博客&#xff08;二&#xff09;- 快速发布到多个渠道一.前言 写博客&#xff0c;可以带给我们很多好处&#xff0c;比如可以让我们结识更多志同道合的人&#xff1b;在写博客过程中…

java appendable,org.eclipse.jetty.util.Utf8Appendable$NotUtf8Exception: Not valid UTF8

上传文件奇怪的错误2016-10-14 11:00:52,254 nuoshang.bluejay.common.shiro.cache.RedisCache.put(RedisCache.java:54) DEBUG - SET nameshiro-activeSessionCache key70qv5bejsihmgot7hroqg6q0lv2016-10-14 11:00:52,254 nuoshang.bluejay.common.shiro.cache.LCache.fire(L…

Oracle高可用概述(HA与RAC的关系解惑)

1.你如何理解高可用的概念&#xff1f; 所谓的高可用HA就是当你的系统中的某个节点异常损坏了&#xff0c;系统还是可用状态&#xff0c;还可以对外提供服务&#xff0c;不会因为你的节点丢失而整体瘫痪。 2.列出你知道的Oracle高可用产品&#xff0c;并作一些功能和应用场景上…

从github clone文件: Failed to receive SOCKS4 connect request ack.

安装了代理&#xff0c;能上网&#xff0c;也能从github上下载文件&#xff0c;就是无法从github上clone文件&#xff0c; 查了很久资料后&#xff0c;终于发现使用sudo可以解决问题。不过&#xff0c;不知道原因是什么&#xff1f; 比如&#xff1a;git clone https://github.…

mxf高速发展和数字电影母版制作技术

1.实现MXF的诺言——格式只是迈向可互操作内容管理的一步 当把元数据加到数字内容的MXF&#xff08;素材交换格式&#xff09;标准通过EBU于2002年推出时&#xff0c;当时曾预期广播机构将会迅速无缝地管理其所有来自不同厂家的制作、后期和分配系统上的数字内容。 六年过…

Android 路由实践(二)

前言继上一篇Android 路由实践&#xff08;一&#xff09;之后&#xff0c;断更已经差不多一个月&#xff0c;毕竟是年前的最后一个月&#xff0c;各种事情扎堆&#xff0c;直到近几天才稍微闲下来&#xff0c;于是有了此文。简单回顾下&#xff0c;上一篇文章中简单介绍了三种…

php中newself(),在php代码中新建对象用到的new self与new static有什么不同

我们在使用php代码新建对象的时候&#xff0c;一般会用到new self与new static,那么它们在使用的时候区别在哪里&#xff1f;先说说new static(),new static与new self一样&#xff0c;在php代码中&#xff0c;它是用来新建一个对象的.那么他们之间的不同之处在哪里呢&#xff…

ORACLE rac集群概念和原理

参考文献&#xff1a; 文献一 文献二 文献三 谢谢作者分享&#xff01;

Python基础-变量作用域

1.函数作用域介绍 函数作用域 Python中函数作用域分为4种情况&#xff1a; L&#xff1a;local&#xff0c;局部作用域&#xff0c;即函数中定义的变量&#xff1a;E&#xff1a;enclosing&#xff0c;嵌套的父级函数的局部作用域&#xff0c;即包含此函数的上级函数的局部作用…

视频源常见接口介绍

在录制和播放中&#xff0c;要通过接口实现文件的传输&#xff0c;下面介绍常用接口。 [AV IN/OUT/PHONES]&#xff1a;这是一个多功能的插孔&#xff0c;在菜单里可以设置其功能。当设置为[IN/OUT]时&#xff0c;此插孔可以输入和输出音频以及视频信号&#xff0c;用于连接电视…

php爱奇艺筛选标签,三种排序 快速筛选好视频_软件资讯技巧应用-中关村在线

使用在线视频播放器来观看视频&#xff0c;通常有可以分为有目标和无目标两种。即是用户如果定点找一部视频和随意查看喜欢的视频&#xff0c;这两种模式往往查找视频的方法也是不一样的。我们这里要和大家讲解的是&#xff0c;用户在没有目标视频的情况下&#xff0c;怎样更快…