python --- 协程编程(第三方库gevent的使用)
1. 什么是协程?
协程(coroutine),又称微线程。协程不是线程也不是进程,它的上下文关系切换不是由CPU控制,一个协程由当前任务切换到其他任务由当前任务来控制。一个线程可以包含多个协程,对于CPU而言,不存在协程这个概念,它是一种轻量级用户态线程(即只针对用户而言)。协程拥有自己的寄存器上下文和栈,协程调度切换到其他协程时,将寄存器上下文和栈保存,在切回到当前协程的时候,恢复先前保存的寄存器上下文和栈。
2. 在编程中为什么要使用协程?
使用协程的好处:(1)CPU无需负担上下文的开销;(2)不需加锁(多个线程操作数据时得加锁);(3)由程序员切换控制流,方便编程;(4)高并发、高扩展、低成本(一个CPU支持上万的协程都不是问题)。
当然,任何事物有优点必有缺点。协程得缺点:(1)协程自己无法利用CPU多核资源(除非与多进程或者多线程配合);(2)遇到阻塞操作会使整个程序阻塞。
例一(使用yield实现在任务间的切换):
import time def func1(name):
print("----func1 start...----")
for i in range(6):
temp = yield #每次遇到yield,func1在此处阻塞,直到temp接收到func2中con.send()传来的值
print("%s in the func1" % (str(temp)))
time.sleep(1) def func2():
print("----func2 start...----")
con.__next__() #此处开始真正的func1的调用
for i in range(5):
con.send(i+1)
print("%s in the func2" % i) if __name__ == '__main__':
con = func1(1) #在有yield的函数中此处不是真正的函数调用,打印con便可知道
# print(con)
p = func2()
使用yield进行任务切换
注:例一严格来说不能算是协程,只是实现了两个任务之间的切换。
3. 既然例一不能算多协程,难么在python中应该如何使用协程?
greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator(例一中的con=func1(1)就是做这个操作)。
例二:
import greenlet def func1():
for i in range(1,6):
print(i)
g2.switch() #切换到g2 def func2():
words = ['a', 'b', 'c', 'd', 'e']
for w in words:
print(w)
g1.switch() #切换到g1 g1 = greenlet.greenlet(func1)
g2 = greenlet.greenlet(func2)
g1.switch() #切换到g1
使用greenlent模块实现任务切换
注:使用greenlent可以很简单的进行多任务之间的切换,但是程序运行最耗时的便是I/O操作,要使用协程实现高并发,应当是一旦遇到I/O操作就切换到其他任务,等I/O操作完成后在切回到当前任务(这个过程应当是自动的)。
4. 那么在python中,如何让任务遇到I/O操作就切换?
我们使用第三方库gevent来实现。
gevent的官方定义:gevent is a coroutine -based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libev event loop.
例三(gevent的简单使用):
import gevent
import time def func1():
print("func1: start.....")
# Put the current greenlet to sleep for at least *seconds*.(模拟I/O操作,任务在此处自动切换)
gevent.sleep(3)
print("func1: end") def func2():
print("func2: start.....")
gevent.sleep(0.5)
print("func2: end") start_time = time.time()
# joinall(greenlets, timeout=None, raise_error=False, count=None)
# Wait for the ``greenlets`` to finish.
# :return: A sequence of the greenlets that finished before the timeout (if any)expired.
gevent.joinall([gevent.spawn(func1),
gevent.spawn(func2)])
# spawn(cls, *args, **kwargs)
# Create a new :class:`Greenlet` object and schedule it to run ``function(*args, **kwargs)``.
# This can be used as ``gevent.spawn`` or ``Greenlet.spawn``. print("cost:", time.time()-start_time)
# 通过计算程序运行的时间可以发现程序确实是以单线程达模拟出了多任务并行的操作。
gevent的简单使用
例四(gevent和urllib配合同时下载多个网页):
import urllib.request
import gevent,time
import gevent.monkey def func(url="", filename=""):
print("Download:%s" % url)
result = urllib.request.urlopen(url) #请求打开一个网页
data = result.read() #读取内容
with open(filename, 'wb') as fp: #写入文档
fp.write(data)
print("Finish:%s" % url) if __name__ == "__main__":
# Do all of the default monkey patching (calls every other applicablefunction in this module).
# 相当与做一个标记,做完此操作gevent就可以检测到此程序中所有的I/O操作
gevent.monkey.patch_all() async_time = time.time()
gevent.joinall([
gevent.spawn(func, "http://www.cnblogs.com/God-Li/p/7774497.html", "7774497.html"),
gevent.spawn(func, "http://www.gevent.org/", "gevent.html"),
gevent.spawn(func, "https://www.python.org/", "python.html"),
])
print("async download cost:", time.time()-async_time) start_time = time.time()
func("http://www.cnblogs.com/God-Li/p/7774497.html", "7774497.html")
func("http://www.gevent.org/", "gevent.html")
func("https://www.python.org/", "python.html")
print("download cost:", time.time()-start_time)
gevent和urllib配合同时下载多个网页
注:对上例代码稍加改造,加上对html源码的解析功能,就可以实现一个简单的多并发爬虫。
对python --- 网络编程Socket中例二的socket_server2使用gevent改造就可以使其成为一个大并发的socket server。
例五(使用gevent实现并发的socket server):
#服务端
import socket
import gevent
import gevent.monkey gevent.monkey.patch_all() def request_handler(conn): '''
Wait for an incoming connection. Return a new socket
representing the connection, and the address of the client.
'''
while True:
# print("ok")
data = conn.recv(1024) #接收信息,写明要接收信息的最大容量,单位为字节
print("server recv:", data)
conn.send(data.upper()) #对收到的信息处理,返回到客户端 if __name__ == "__main__":
address = ("localhost", 6666) # 写明服务端要监听的地址,和端口号
server = socket.socket() # 生成一个socket对象
server.bind(address) # 用socket对象绑定要监听的地址和端口
server.listen() # 开始监听 while True:
conn, addr = server.accept() # 等带新连接接入服务端,返回一个新的socket对象和地址,地址格式同前面格式
gevent.spawn(request_handler, conn) server.close() # 关闭服务端
socket_server2的并发实现
注:可使用python --- 网络编程Socket中例二的socket_client2进行测试。
python --- 协程编程(第三方库gevent的使用)的更多相关文章
- python协程详解,gevent asyncio
python协程详解,gevent asyncio 新建模板小书匠 #协程的概念 #模块操作协程 # gevent 扩展模块 # asyncio 内置模块 # 基础的语法 1.生成器实现切换 [1] ...
- python基于协程的网络库gevent、eventlet
python网络库也有了基于协程的实现,比较著名的是 gevent.eventlet 它两之间的关系可以参照 Comparing gevent to eventlet, 本文主要简单介绍一下event ...
- day-5 python协程与I/O编程深入浅出
基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1. 什么是协程(以下内容来自维基百 ...
- python中的协程:greenlet和gevent
python中的协程:greenlet和gevent 协程是一中多任务实现方式,它不需要多个进程或线程就可以实现多任务. 1.通过yield实现协程: 代码: import time def A(): ...
- Python协程(真才实学,想学的进来)
真正有知识的人的成长过程,就像麦穗的成长过程:麦穗空的时候,麦子长得很快,麦穗骄傲地高高昂起,但是,麦穗成熟饱满时,它们开始谦虚,垂下麦芒. --蒙田<蒙田随笔全集> *** 上篇论述了关 ...
- Python协程与Go协程的区别二
写在前面 世界是复杂的,每一种思想都是为了解决某些现实问题而简化成的模型,想解决就得先面对,面对就需要选择角度,角度决定了模型的质量, 喜欢此UP主汤质看本质的哲学科普,其中简洁又不失细节的介绍了人类 ...
- python 协程与go协程的区别
进程.线程和协程 进程的定义: 进程,是计算机中已运行程序的实体.程序本身只是指令.数据及其组织形式的描述,进程才是程序的真正运行实例. 线程的定义: 操作系统能够进行运算调度的最小单位.它被包含在进 ...
- Python协程与JavaScript协程的对比
前言 以前没怎么接触前端对JavaScript 的异步操作不了解,现在有了点了解一查,发现 python 和 JavaScript 的协程发展史简直就是一毛一样! 这里大致做下横向对比和总结,便于对这 ...
- [转载] Python协程从零开始到放弃
Python协程从零开始到放弃 Web安全 作者:美丽联合安全MLSRC 2017-10-09 3,973 Author: lightless@Meili-inc Date: 2017100 ...
随机推荐
- asp.net或javascript判断是否手机访问
/// <summary> /// 判断手机用户UserAgent /// </summary> /// <returns></returns> pri ...
- ELK日志收集分析系统配置
ELK是日志收益与分析的利器. 1.elasticsearch集群搭建 略 2.logstash日志收集 我这里的实现分如下2步,中间用redis队列做缓冲,可以有效的避免es压力过大: 1.n个ag ...
- java8中Stream数据流
筛选重复的元素 Stream 接口支持 distinct 的方法, 它会返回一个元素(根据流所生成元素的 hashCode和equals方法实现)的流. 例如,以下代码会筛选出列表中所有的偶数,并确保 ...
- 《阿里巴巴Java开发规约》插件使用介绍
一.简介 阿里巴巴于10月14日在杭州云栖大会上,正式发布了<阿里巴巴Java开发规约>扫描插件!该插件基于<阿里巴巴Java开发规约>手册内容,在扫描代码后,将不符合规约的代 ...
- 如何删除错误提交的 git 大文件
早上小伙伴告诉我,他无法拉下代码,我没有在意.在我开始写代码的时候,发现我的 C 盘炸了.因为我的磁盘是苏菲只有 256G 放了代码就没空间了,于是我查找到了原来是我的代码占用了居然有 2000+M ...
- 张高兴的 Windows 10 IoT 开发笔记:BH1750FVI 光照度传感器
BH1750FVI 是一款 IIC 接口的数字型光强度传感器集成电路.下面介绍一下其在 Windows 10 IoT Core 环境下的用法. 项目运行在 Raspberry Pi 2/3 上,使用 ...
- 三、Spring的面向切面
Spring的面向切面 在应用开发中,有很多类似日志.安全和事务管理的功能.这些功能都有一个共同点,那就是很多个对象都需要这些功能.复用这些通用的功能的最简单的方法就是继承或者委托.但是当应用规模达到 ...
- 从canvas理解面向对象
前言 据说在编程语言的发展过程中,面向对象语言的出现是为了解决GUI编程的问题而出现的.计算机一开始是用纸带,命令行等来和人进行交互,而图形界面的出现是一次重大的改进,使普通人很容易就能使用计算机. ...
- chromium 34以后中文字体粗体渲染问题
估计不少人更新后都遇到这个情况了吧,粗体渲染如然变得很模糊,很奇怪,Google下说是字体实现方式变了,国内一些网站用的中文字体都是宋体,但是宋体本身没有粗体,Win下的粗体是微软自己通过某种方式实现 ...
- mysql安装教程以及配置快捷方式
1.首先双击exe 3.Next 安装过程省略.... Win+r 然后输入:cmd 打开dos窗口后: 输入: mysql -uroot -p你设置的密码 案例:mysql -uroot -proo ...