协程-遇到I/O自动切换
参考博客:http://www.cnblogs.com/alex3714/articles/5248247.html
一、前言
Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
二、Gevent
- import gevent
- def func1():
- print('running in func1...')
- gevent.sleep(2) # I/O中断2秒
- print('Explicit context switch to func1 again...')
- def func2():
- print('Explicit context func2...')
- gevent.sleep(1)
- print('Implicit context switch to func2 again...')
- gevent.joinall([
- gevent.spawn(func1),
- gevent.spawn(func2),
- ])
- import gevent
- def func1():
- print('running in func1...')
- gevent.sleep(2)
- print('Explicit context switch to func1 again...')
- def func2():
- print('Explicit context func2...')
- gevent.sleep(1)
- print('Implicit context switch to func1 again...')
- def func3():
- print('running in func3...')
- gevent.sleep(0) # 表示中断,没有时间
- print('running func3 again...')
- gevent.joinall([
- gevent.spawn(func1),
- gevent.spawn(func2),
- gevent.spawn(func3),
- ])
三、遇到I/O阻塞时自动切换任务
简单的gevent并发爬网页
- # -*- coding: UTF-8 -*-
- from urllib import request
- import time
- from gevent import monkey
- import gevent
- monkey.patch_all()
- # gevent并不能识别urllib 的I/O中断,monkey.patch_all会给所有I/O中断做标签
- def f(url):
- print('Get: %s' % url)
- resp = request.urlopen(url)
- data = resp.read()
- print('%d bytes received from %s.' % (len(data), url))
- # 同步处理
- urls = [
- 'https://www.python.org/',
- 'https://www.yahoo.com/',
- 'https://github.com/'
- ]
- time_start = time.time()
- for url in urls:
- f(url)
- print('同步take %s seconds' % (time.time() - time_start))
- # 异步处理
- async_time = time.time()
- gevent.joinall([
- gevent.spawn(f, 'https://www.python.org/'),
- gevent.spawn(f, 'https://www.yahoo.com/'),
- gevent.spawn(f, 'https://github.com/')
- ])
- print('异步take %s seconds' % (time.time() - async_time))
结果:
- Get: https://www.python.org/
- 48956 bytes received from https://www.python.org/.
- Get: https://www.yahoo.com/
- 517389 bytes received from https://www.yahoo.com/.
- Get: https://github.com/
- 51473 bytes received from https://github.com/.
- 同步take 4.6533966064453125 seconds
- Get: https://www.python.org/
- Get: https://www.yahoo.com/
- Get: https://github.com/
- 48956 bytes received from https://www.python.org/.
- 521617 bytes received from https://www.yahoo.com/.
- 51473 bytes received from https://github.com/.
- 异步take 1.916191816329956 seconds
- # 可以看到两者之间时间差别还是很大的
如果没有monkey.patch_all(),程序也能正常运行,但是同步和异步时间基本没有差别,因为gevent并不知道urllib的I/O中断,所以也不会自动切换,所以哪怕使用了gevent,程序也是同步执行(串行)。而monkey.patch_all()就可以为所有urllib中的I/O中断做标记,gevent遇到这些中断就会自动切换,执行其他没有I/O操作的程序。
四、gevent实现单线程下的多socket并发
server side
- 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)
- 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 side
- 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()
- # 并发100 个socket连接
- 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()
协程-遇到I/O自动切换的更多相关文章
- 【python】-- 协程介绍及基本示例、协程遇到IO操作自动切换、协程(gevent)并发爬网页
协程介绍及基本示例 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他 ...
- 利用协程爬网页,自动切换io 精典案例:
首先Python提供的协程库gevent好像并不能知道那些程序使用了io 所以要加一个补丁,mondey,以下同步和异步各爬一次的案例 : , from urllib import requesti ...
- flask之分析线程和协程
flask之分析线程和协程 01 思考:每个请求之间的关系 我们每一个请求进来的时候都开一个进程肯定不合理,那么如果每一个请求进来都是串行的,那么根本实现不了并发,所以我们假定每一个请求进来使用的是线 ...
- Flask 之分析线程和协程
目录 flask之分析线程和协程 01 思考:每个请求之间的关系 02 threading.local 03 通过字典自定义threading.local 04 通过setattr和getattr实现 ...
- 网络编程基础--协程--greenlet切换---gevent自动识别 IO ---
协程: 1 单线程来实现并发---协程: 协程:是单线程下的并发,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程, 即协程是由用户程序自己控制调度的 只 ...
- Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)
Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...
- 并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_208 协程与线程向来焦孟不离,但事实上是,线程更被我们所熟知,在Python编程领域,单核同时间内只能有一个线程运行,这并不是什么 ...
- 异步、+回调机制、线程queue、线程Event、协程、单线程实现遇到IO切换
# from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # import requests # import o ...
- PHP下的异步尝试三:协程的PHP版thunkify自动执行器
PHP下的异步尝试系列 如果你还不太了解PHP下的生成器和协程,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunk ...
随机推荐
- redis与mysql性能对比、redis缓存穿透、缓存雪崩
写在开始 redis是一个基于内存hash结构的缓存型db.其优势在于速读写能力碾压mysql.由于其为基于内存的db所以存储数据量是受限的. redis性能 redis读写性能测试redis官网测试 ...
- java-HttpGetPost-图片字节流上传
在java程序开发中经常用到与服务端的交互工作,主要的就是传递相应的参数请求从而获取到对应的结果加以处理 可以使用Get请求与Post请求,注意!这里的Get请求不是通过浏览器界面而是在程序代码中设置 ...
- 由A到D中间可不止“B、C”
在电子信息系统的学习中,我们或许早就被告知现实世界是模拟的,而数字化的模拟世界则越来越展现更多的风采.但是所谓的数字和模拟只是相对的而已,你可以把模拟量当做无穷数字量的组合,也可以把数字量当做具有不同 ...
- CF刷刷水题找自信1
CF 1108A Two distinct points 题目意思:给你两个线段的起点和终点,让你给出两个不同的点,这两点分别处于两个不同的线段之中.解题思路:题目说如果存在多种可能的点,随意一组答案 ...
- 团队Alpha冲刺(二)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:丹丹 组员7:家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示组内 ...
- myeclipse和ecplise中安装git插件的问题
我的myeclipse10.7和ecplise helis一直安装不了git插件,myeclipse中details说我的myeclipse少了team_features等之类文件,helis的情况大 ...
- EasyUI中DataGrid构建复合表头
在使用easyui的DataGrid控件时,构建复合表头就显得非常简单了.只需要在使用columns属性时通过数组的方式编写列名即可.如我们需要构建成一个如下的表头: Columns的代码如下: co ...
- 一个form表单,多个提交按钮
技巧就是把提交的input的类型改成button!这样就可以实现多个按钮提交! 以下是案例: <form action="" id="tijiao"> ...
- MySql中的varchar类型
转载:http://www.cnblogs.com/doit8791/archive/2012/05/28/2522556.html 1.varchar类型的变化 MySQL 数据库的varchar类 ...
- Django之ORM对数据库操作
基本操作 <1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> get(**kwargs): ...