Python基础 协程
1 协程的介绍
协程:协助程序,线程和进程都是抢占式特点,线程和进程的切换我们是不能参与的。
而协程是非抢占式特点,协程也存在着切换,这种切换是由我们用户来控制的。
协程主解决的是IO的操作。
协程,又称微线程,纤程。英文名Coroutine。
优点1: 协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
优点2: 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
2 协程的方法
1 yield 的简单实现
这是一个生成器,调用的时候才执行
def consumer(name):
print('消费者:--ready to eat bozi...--')
while True:
# new_baozi 接受调用生成器的值
new_baozi = yield
print('[%s] is eating baozi %s' % (name), new_baozi)
time.sleep(1)
def produer():
# 让两个生成器先执行一次到yield
r = con.__next__()
r = con2.__next__()
n = 1
while True:
# time.sleep(1)
print('\033[32;lm[producer]\033[0m is making baozi %s and %s' % (n, n + 1))
# 调用生成器并发送数据
con.send(n)
con2.send(n + 1)
n += 2
if __name__ == '__main__':
con = consumer('c1')
con2 = consumer('c2')
p = produer()
2 , greenlet 模块
greenlet 是一个用c 实现的协程模块,相比于python自带的yield ,他可以使你在任意函数之间切换,而不需要把这个函数先声明为generator
greenlet 是第三方模块 需要下载才能使用
gr1 = greenlet(目标函数)
gr2 = switch() 切换执行
import greenlet
import time
def test1():
while True:
print('test1...')
time.sleep(0.5)
g2.switch() # 让程序去g1指定的目标执行
def test2():
while True:
print('test2...')
time.sleep(0.5)
g1.switch()
if __name__ == '__main__':
# test1()
# test2()
g1 = greenlet.greenlet(test1) #指定g1的执行目标
g2 = greenlet.greenlet(test2)
g1.switch()
print('程序结束了。。')
3, geven 模块
geven同样为第三方模块
import time
#如果程序中 没有耗时操作 就按照顺序执行
def test1():
for i in range(5):
print('test1....',i)
gevent.sleep(0.5) #注意 只有使用gevent耗时操作才能自动耗时操作
def test2():
for i in range(5):
print('test2....',i)
gevent.sleep(0.5)
if __name__ == '__main__':
g1 = gevent.spawn(test1)
g2 = gevent.spawn(test2)
g1.join()
g2.join() #等待g1 g2 的目标执行完后才向下进行
print('程序结束了')
gevent 中的monkey.patch 补丁
import time
from gevent import monkey
#打补丁
monkey.patch_all()
#如果程序中 没有耗时操作 就按照顺序执行
def test1():
for i in range(5):
print('test1....',i)
time.sleep(0.5) #注意 只有使用gevent耗时操作才能自动耗时操作
def test2():
for i in range(5):
print('test2....',i)
time.sleep(0.5)
if __name__ == '__main__':
gevent.joinall([
gevent.spawn(test1),
gevent.spawn(test2)
]) #简化写法
print('程序结束了')
4 使用协程下载图片
会用到第三方模块 requests 模块(包)获取图片的本质其实是为了获取图片的二进制数据,
我们将这些二进制数据下载来翻译之后就成了我们想要的图片了
首先给大家展示一下不需要些协程的版本
import requests
url2 = 'https://b-ssl.duitang.com/uploads/item/201612/10/20161210005234_hZzLn.jpeg'
response = requests.get(url2)
# response.content #获取图片的二进制数据
with open('1.jpeg', mode='wb') as f:
f.write(response.content)
不使用协程的情况,如果遇到网络卡顿或者其他的问题 脚本文件会一直阻塞或者等待,不能跳过问题去找下一张
但是使用协程会大大加快工作效率,将任务布置之后,遇到问题图片可以自己跳过,进行下一张
代码展示:
import requests
import gevent
def download_img(url,img_name):
response = requests.get(url)
with open('img/'+ img_name,mode='wb') as f :
f.write(response.content)
if __name__ == '__main__':
url ='https://ossweb-img.qq.com/images/lol/web201310/skin/big34007.jpg'
url2 ='https://ossweb-img.qq.com/images/lol/web201310/skin/big412006.jpg'
download_img(url,'mao.jpg')
download_img(url2, 'kaola.jpeg')
gevent.joinall([
gevent.spawn(download_img,url,'mao.jpeg'),
gevent.spawn(download_img,url2,'kaola.jpg')
])
两张LOL的皮肤图片,庆典女皇 艾维尼亚 和 西部魔影 锤石
- python和C语言混编的几种方式
- 通过“四大行为”对WCF的扩展[实例篇]
- 古中国数学家的计算力真是惊人
- 基于Apache Spark机器学习的客户流失预测
- 数据库连接字符串的处理方法!加密解密连接字符串。
- ASP.net实现无扩展名的URL重写。简单、方便、无需ISAPI。
- 通过自定义ServiceHost实现对WCF的扩展[实例篇]
- 通过自定义ServiceHost实现对WCF的扩展[原理篇]
- python使用rsa库做公钥解密(网上别处找不到)
- 通过“四大行为”对WCF的扩展[原理篇]
- WCF客户端运行时架构体系详解[下篇]
- WCF客户端运行时架构体系详解[上篇]
- WCF服务端运行时架构体系详解[续篇]
- [WCF-Discovery] 实例演示:如何利用服务发现机制实现服务的“动态”调用?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 听说你一读Spring源码就懵?我帮你把架子搭好了,你填就行!
- 机器学习感兴趣么?无监督的遥感图像分类感兴趣吗?来嘛!
- 仓库ERP管理系统(springboot)
- R海拾遗-shiny4
- Spring中眼见为虚的 @Configuration 配置类
- 微信6.6.7版本后图文分享无标题的分析
- GEO 数据挖掘-数据获得
- POI和EasyExcel-你还在为导入导出数据苦恼吗?
- geo数据挖掘-2
- 基于ssm的客户管理系统
- 牛逼哄哄的Spring是怎么被MyBatis给征服了?
- Flutter如何和Native通信-Android视角
- 面试问倒无数人的Spring事务问题,就被你这样说完了?
- GEO数据挖掘3
- 史上最全Docker初学者命令大全