协程--gevent模块(单线程高并发)
先恶补一下知识点,上节回顾
上下文切换:当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的数据,程序指针等,然后载入另一个线程的本地数据,程序指针等,最后才开始执行。这种切换称为“上下文切换”(“context switch”)
CPU会在一个上下文中执行一个线程,然后切换到另外一个上下文中执行另外一个线程,上下文切换并不廉价。如果没有必要,应该减少上下文切换的发生
进程: 一个程序需要运行所需的资源的集合
每个进程数据是独立的
每个进程里至少有一个线程
每个进程里有可以多有个线程
线程数据是共享的
进程间共享数据的代价是高昂的,所以要尽量避免进程间的数据共享
线程间的数据本来就是共享的
线程要修改同一份数据,必须加锁,互斥锁mutex
生产者消费者:1.解耦2.提高程序的运行效率,把中间等待的时间省去 多线程场景: IO密集型,因为IO操作基本不占用CPU,所以多用在web,爬虫,socket交互
多进程场景:CPU密集型,大数据分析,金融分析,这样用的IO就很少,因为这个进程会进行大量的运算, 但是如果切换了进程,就会变慢
协程
协程:微线程, 协程是一种用户态的轻量级线程,CPU不知道它的存在,
协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,
因此协程能保留上一次调用时的状态(即所有局部状态的一个特定组合,),每次过程重入时,就相当于上一次调用的状态, 也就是进入上一次离开时所处逻辑流的位置
协程的好处:(是程序级别切换,CPU是不知道的.)
1.无需线程上下文切换,
2.无需原子操作锁定及同步开销 , 什么是原子操作? :是不需要同步的!!,是指不会被线程调度打断的操作;这种操作一旦开始,就运行到结束,中间不会有任何 context switch(切换到另一个线程,)
原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心
3.方便切换控制流,简化编程模型
4.高并发 + 高扩展 + 低成本 : 一个CPU支持上万的协程都不是问题,所以很适合用于高并发处理
坏处-----:
1.无法利用多核资源,协程的本质是个单线程,它不能同时将单个CPU的多个核用上, 协程需要配合进程才能在多CPU上, 适用于CPU密集型应用
2.进程阻塞 (Blocking) 操作 如IO操作时,会阻塞掉整个程序
----什么条件符合才能称之为协程?
A.必须在只有一个单线程里实现并发
B.修改共享数据不需要加锁
C.用户程序里自己保持多个控制流的上下文栈
D.一个协程遇到IO操作自动切换到其他协程!!!!!!
重点来了。。。。。 大量的模块知识点---我希望我以后还能记起来----汗颜!
Greenlet模块
greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator(生成器)
from greenlet import greenlet def test1():
print('test1:我是1')
gr2.switch() #切换到test2
print('test1:我是1.1')
gr2.switch()
def test2():
print('test2:我是2')
gr1.switch() #切换到test1
print('test2:我是2.2') gr1=greenlet(test1)
gr2=greenlet(test2)
gr1.switch() #先切换到test1
>>
test1:我是1
test2:我是2
test1:我是1.1
test2:我是2.2
swich() 就是切换, 按执行顺序-- 但是遇到IO操作 好像并没有自动切换
Gevent模块
Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
这里使用gevent.sleep 来获取控制权
import gevent def func1():
print('\033[31;1m我是func1\033[0m')
gevent.sleep(3)
print('\033[31;1m我是func1.1--我上面有3秒\033[0m') def func2():
print('\033[32;1m我是func2.\033[0m')
gevent.sleep(2)
print('\033[32;1m我是func2.1 我上面有2秒\033[0m') def func3():
print('\033[32;1m我是func3.\033[0m')
gevent.sleep(2)
print('\033[32;1m我是func3.1我上面有2秒\033[0m') gevent.joinall([gevent.spawn(func1),
gevent.spawn(func2),
gevent.spawn(func3),])
这里会按照sleep 设置来执行 一定会先打印出func2-->func3-->func1
同步和异步的性能区别
import gevent def 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)]
threads=[]
for i in range(10):
threads.append(gevent.spawn(task,i))
gevent.joinall(threads) #执行流程只会在 所有greenlet执行完后才会继续向下走 print('Synchronous:')
synchronous() print('Asynchronous:')
asynchronous()
Synchrounous:定义了同步的函数:定义一个for循环。依次把内容传输给task函数,然后打印执行结果-----
Aynchrounous:定义了异步的函数: 这里用到了一个gevent.spawn方法,就是产生的意思. gevent.joinall 也就是等待所以操作都执行完毕
gevent.spawn 可以调用函数
可是我们一般也不会这么用。去故意的设置一个gevent.sleep来切换 ,下面就来在实际场景中应用
遇到IO阻塞,自动切换任务
这里就用到了简单的网页爬虫环境中, 操作IO的时候。自动切换。这里就用到了猴子补丁(monkey.patch_all(), 知道这是运行时,动态修改已有的代码,而不需要修改原始代码
)
from gevent import monkey
import gevent
import time
from urllib.request import urlopen
monkey.patch_all()
#对比得出 协程 运行出的更快
#IO阻塞 自动切换任务。。
def say(url):
print('get url',url)
resp = urlopen(url)
data = resp.read()
print(len(data),url)
t1_start = time.time()
say('http://www.xiaohuar.com/')
say('http://www.oldboyedu.com/')
print("普通--time cost",time.time() - t1_start) t2_stat = time.time()
gevent.joinall(
[gevent.spawn(say,'http://www.xiaohuar.com/'),
gevent.spawn(say,'http://www.oldboyedu.com/'),
gevent.spawn(say,'http://weibo.com/MMbdzx?from=myfollow_all&is_all=1#_rnd1482040021384')]
)
print("gevent---time cost",time.time() - t2_stat)
由于切换时再IO操作就自动完成,所以需要gevent修改py自带的标准库,这一过程在启动时通过monkey patch完成 --
对比2次运行完毕的时间,很明显的看到gevent在处理上,更加有优势,
到了这里简单的就算完了。。。来进入总结概念的部分--------http://www.cnblogs.com/zcqdream/p/6196948.html
通过gevent来实现单线程下的多socket并发
server 端,采用gevent协程
import sys
import socket
import time
import gevent from 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) #gevent.spwan调用handle参数并传参 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 socket HOST = '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()
多线程客户端去请求
import socket
import threading def sock_conn(): client = socket.socket() client.connect(("localhost",8001))
count = 0
while True:
#msg = input(">>:").strip()
#if len(msg) == 0:continue
client.send( ("hello %s" %count).encode("utf-8")) data = client.recv(1024) print("[%s]recv from server:" % threading.get_ident(),data.decode()) #结果
count +=1
client.close() for i in range(100):
t = threading.Thread(target=sock_conn)
t.start()
协程--gevent模块(单线程高并发)的更多相关文章
- python编程中的并发------协程gevent模块
任务例子:喝水.吃饭动作需要耗时1S 单任务:(耗时20s) for i in range(10): print('a正在喝水') time.sleep(1) print('a正在吃饭') time. ...
- 协程:gevent模块,遇到i/o自动切换任务 038
协程 : gevent模块,遇到io自动切换任务 from gevent import monkey;monkey.patch_all() # 写在最上面 这样后面的所有阻塞就全部能够识别了 impo ...
- python之协程gevent模块
Gevent官网文档地址:http://www.gevent.org/contents.html 进程.线程.协程区分 我们通常所说的协程Coroutine其实是corporate routine的缩 ...
- python 并发编程 协程 gevent模块
一 gevent模块 gevent应用场景: 单线程下,多个任务,io密集型程序 安装 pip3 install gevent Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步 ...
- python协程--asyncio模块(基础并发测试)
在高并发的场景下,python提供了一个多线程的模块threading,但似乎这个模块并不近人如意,原因在于cpython本身的全局解析锁(GIL)问题,在一段时间片内实际上的执行是单线程的.同时还存 ...
- 进程池和线程池、协程、TCP单线程实现并发
一.进程池和线程池 当被操作对象数目不大时,我们可以手动创建几个进程和线程,十几个几十个还好,但是如果有上百个上千个.手动操作麻烦而且电脑硬件跟不上,可以会崩溃,此时进程池.线程池的功效就能发挥了.我 ...
- 协程gevent模块和猴子补丁
# pip 装模块 greenlet和gevent # 协程 # 与进程.线程一样也是实现并发的手段 # 创建一个线程.关闭一个线程都需要创建寄存器.栈等.需要消耗时间 # 协程本质上是一个线程 # ...
- 协程----greenlet模块,gevent模块
1.协程初识,greenlet模块 2.gevent模块(需要pip安装) 一.协程初识,greenlet模块: 协程:是单线程下的并发,又称微线程,纤程.英文名Coroutine.一句话说明什么是线 ...
- Python之路(第四十七篇) 协程:greenlet模块\gevent模块\asyncio模块
一.协程介绍 协程:是单线程下的并发,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 协程相比于线程,最大的区别在于 ...
随机推荐
- CSS布局 - 三栏布局
CSS布局技术可谓是前端技术中最基础的技术,就是因为基础,所以我认为要更加熟练,深入的去掌握,去梳理. 一. 传统 ---> 浮动实现的三栏布局 采用浮动实现的三栏布局有以下特点及注意事项: · ...
- Kafka如何创建topic?
Kafka创建topic命令很简单,一条命令足矣:bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-facto ...
- C# 3.0新语言特性和改进(一)
引言 关于C#3.0的特性,园子里已经有了一大把,可能大家都很熟悉了,虽然本人开发中使用过,但自己还是需要记录一下,总结一下.同时也是后面写Linq知识的基础.希望有兴趣的朋友,可以看看. C# 3. ...
- C#——this关键字(1)
//我的C#是跟着猛哥(刘铁猛)(算是我的正式老师)<C#语言入门详解>学习的,微信上猛哥也给我讲解了一些不懂得地方,对于我来说简直是一笔巨额财富,难得良师! 在学习C#的时候,老师讲的示 ...
- C# - 多线程 之 Process与Thread与ThreadPool
Process 进程类, // 提供对本地和远程进程的访问,启动/停止本地系统进程 public class Process : Component { public int Id { get; } ...
- asp.net MVC5 学习笔记(一)
Html.ActionLink("linkText","actionName") 该重载的第一个参数是该链接要显示的文字,第二个参数是对应的控制器的方法,默认控 ...
- 织梦cms常用标签
dedecms简介:织梦内容管理系统(DedeCms) 以简单.实用.开源而闻名,是国内知名的PHP开源网站管理系统,也是使用用户较多的PHP类CMS系统,在经历多年的发展,目前的版本无论在功能,还是 ...
- GJM :Unity集成Leap Motion
Demo演示视频
- UITextField
UITextFieldDemo 效果 特点 1.有效定制键盘的样式 2.处理键盘对文本框的遮挡 用法 1.导入文件(UITextField+CreateInputAccessoryView.h/.m) ...
- SQL Server附加数据库失败错误号:5120的解决办法
附加数据库时出现附加数据库失败的错误,错误号是5120,已经两次遇到这种问题了.今天写一下解决办法. 有两个方法,很简单: 1.设置mdf文件所在文件夹的权限,在文件夹上右击——属性——安全,如图所示 ...