python编程使用协程并发的优缺点


Posted in Python onSeptember 20, 2018

协程

协程是一种用户态的轻量级线程,又称微线程。

协程拥有自己的寄存器上下文和栈,调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

优点:

1.无需线程上下文切换的开销
2.无需原子操作锁定及同步的开销
3.方便切换控制流,简化编程模型
4.高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。

原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。

缺点:

1.无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
2.进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

使用Gevent

gevent是python的一个并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效.

•简单示例

gevent的sleep可以交出控制权,当我们在受限于网络或IO的函数中使用gevent,这些函数会被协作式的调度, gevent的真正能力会得到发挥。Gevent处理了所有的细节, 来保证你的网络库会在可能的时候,隐式交出greenlet上下文的执行权。

import gevent
def foo():
  print('running in foo')
  gevent.sleep(0)
  print('com back from bar in to foo')
def bar():
  print('running in bar')
  gevent.sleep(0)
  print('com back from foo in to bar')
# 创建线程并行执行程序
gevent.joinall([
  gevent.spawn(foo),
  gevent.spawn(bar),
])

执行结果

running in foo
running in bar
com back from bar in to foo
com back from foo in to bar

•同步异步

import random
import gevent
def task(pid):
  gevent.sleep(random.randint(0, 2) * 0.001)
  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)
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 1 done

Task 4 done

Task 5 done

Task 9 done

Task 6 done

Task 0 done

Task 2 done

Task 3 done

Task 7 done

Task 8 done

•以子类的方法使用协程

可以子类化Greenlet类,重载它的_run方法,类似多线线程和多进程模块

import gevent
from gevent import Greenlet
class Test(Greenlet):
  def __init__(self, message, n):
    Greenlet.__init__(self)
    self.message = message
    self.n = n
  def _run(self):
    print(self.message, 'start')
    gevent.sleep(self.n)
    print(self.message, 'end')
tests = [
  Test("hello", 3),
  Test("world", 2),
]
for test in tests:
  test.start() # 启动
for test in tests:
  test.join() # 等待执行结束

•使用monkey patch修改系统标准库(自动切换协程)

当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。

由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成

import gevent
import requests
from gevent import monkey
monkey.patch_socket()
def task(url):
  r = requests.get(url)
  print('%s bytes received from %s' % (len(r.text), url))
gevent.joinall([
  gevent.spawn(task, 'https://www.baidu.com/'),
  gevent.spawn(task, 'https://www.qq.com/'),
  gevent.spawn(task, 'https://www.jd.com/'),
])

执行输出

2443 bytes received from https://www.baidu.com/

108315 bytes received from https://www.jd.com/

231873 bytes received from https://www.qq.com/

可以看出3个网络操作是并发执行的,而且结束顺序不同

参考链接:http://hhkbp2.github.io/gevent-tutorial/

总结

以上所述是小编给大家介绍的python编程使用协程并发的优缺点,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
Python 由字符串函数名得到对应的函数(实例讲解)
Aug 10 Python
Python实现二维数组按照某行或列排序的方法【numpy lexsort】
Sep 22 Python
Python中Unittest框架的具体使用
Aug 27 Python
Python 通过截图匹配原图中的位置(opencv)实例
Aug 27 Python
python保存log日志,实现用log日志画图
Dec 24 Python
Python爬虫库requests获取响应内容、响应状态码、响应头
Jan 25 Python
解决paramiko执行命令超时的问题
Apr 16 Python
pandas dataframe 中的explode函数用法详解
May 18 Python
Python下载的11种姿势(小结)
Nov 18 Python
Python中读取文件名中的数字的实例详解
Dec 25 Python
pytorch实现ResNet结构的实例代码
May 17 Python
利用For循环遍历Python字典的三种方法实例
Mar 25 Python
详解Numpy中的广播原则/机制
Sep 20 #Python
Python 读写文件的操作代码
Sep 20 #Python
python使用多进程的实例详解
Sep 19 #Python
Anaconda2 5.2.0安装使用图文教程
Sep 19 #Python
win10系统下Anaconda3安装配置方法图文教程
Sep 19 #Python
Window 64位下python3.6.2环境搭建图文教程
Sep 19 #Python
win10下python3.5.2和tensorflow安装环境搭建教程
Sep 19 #Python
You might like
PHP的mysqli_select_db()函数讲解
2019/01/23 PHP
PHP读取文件或采集时解决中文乱码
2021/03/09 PHP
如果文字过长,则将过长的部分变成省略号显示
2006/06/26 Javascript
javascript 字符 Escape,encodeURI,encodeURIComponent
2009/07/09 Javascript
javascript 45种缓动效果 非常酷
2011/06/28 Javascript
Javascript实现图片轮播效果(一)让图片跳动起来
2016/02/17 Javascript
Angular指令封装jQuery日期时间插件datetimepicker实现双向绑定示例
2017/01/22 Javascript
用 js 的 selection range 操作选择区域内容和图片
2017/04/18 Javascript
jQuery加密密码到cookie的实现代码
2017/04/18 jQuery
解决vue的变量在settimeout内部效果失效的问题
2018/08/30 Javascript
微信小程序中的店铺评分组件及vue中用svg实现的评分显示组件
2018/11/16 Javascript
vue+vuex+json-seiver实现数据展示+分页功能
2019/04/11 Javascript
微信端调取相册和摄像头功能,实现图片上传,并上传到服务器
2019/05/16 Javascript
判断“命令按钮”是否被鼠标单击详解
2019/07/31 Javascript
[52:22]EG vs VG Supermajor小组赛B组 BO3 第一场 6.2
2018/06/03 DOTA
python base64 decode incorrect padding错误解决方法
2015/01/08 Python
十个Python程序员易犯的错误
2015/12/15 Python
python定时关机小脚本
2018/06/20 Python
Python 比较文本相似性的方法(difflib,Levenshtein)
2018/10/15 Python
Python生成指定数量的优惠码实操内容
2019/06/18 Python
java中的控制结构(if,循环)详解
2019/06/26 Python
解决Pycharm的项目目录突然消失的问题
2020/01/20 Python
Python随机数函数代码实例解析
2020/02/09 Python
Python3中configparser模块读写ini文件并解析配置的用法详解
2020/02/18 Python
Python实现AI换脸功能
2020/04/10 Python
python开发前景如何
2020/06/11 Python
豆腐の盛田屋官网:日本自然派的豆乳面膜、肥皂、化妆水、乳液等
2016/10/08 全球购物
学前教育专业毕业生自荐信
2013/10/03 职场文书
销售员求职个人的自我评价
2014/02/19 职场文书
面试必备的求职信
2014/05/25 职场文书
2014年党风廉政建设工作总结
2014/11/19 职场文书
合同审查法律意见书
2015/06/04 职场文书
公司费用报销管理制度
2015/08/04 职场文书
导游词之云南丽江-泸沽湖
2019/09/26 职场文书
go 原生http web 服务跨域restful api的写法介绍
2021/04/27 Golang
修改Nginx配置返回指定content-type的方法
2022/09/23 Servers