最近开始研究Python的并行开发技术,包括多线程,多进程,协程等。逐步整理了网上的一些资料,今天整理一下greenlet相关的资料。

并发处理的技术背景

并行化处理目前很受重视, 因为在很多时候,并行计算能大大的提高系统吞吐量,尤其在现在多核多处理器的时代, 所以像lisp这种古老的语言又被人们重新拿了起来, 函数式编程也越来越流行。 介绍一个python的并行处理的一个库: greenlet。 python 有一个非常有名的库叫做 stackless ,用来做并发处理, 主要是弄了个叫做tasklet的微线程的东西, 而greenlet 跟stackless的最大区别是, 他很轻量级?不够, 最大的区别是greenlet需要你自己来处理线程切换, 就是说,你需要自己指定现在执行哪个greenlet再执行哪个greenlet。

greenlet的实现机制

以前使用python开发web程序,一直使用的是fastcgi模式.然后每个进程中启动多个线程来进行请求处理.这里有一个问题就是需要保证每个请求响应时间都要特别短,不然只要多请求几次慢的就会让服务器拒绝服务,因为没有线程能够响应请求了.平时我们的服务上线都会进行性能测试的,所以正常情况没有太大问题.但是不可能所有场景都测试到.一旦出现就会让用户等好久没有响应.部分不可用导致全部不可用.后来转换到了coroutine,python 下的greenlet.所以对它的实现机制做了一个简单的了解.
每个greenlet都只是heap中的一个python object(PyGreenlet).所以对于一个进程你创建百万甚至千万个greenlet都没有问题.

typedef struct _greenlet {PyObject_HEADchar* stack_start;char* stack_stop;char* stack_copy;intptr_t stack_saved;struct _greenlet* stack_prev;struct _greenlet* parent;PyObject* run_info;struct _frame* top_frame;int recursion_depth;PyObject* weakreflist;PyObject* exc_type;PyObject* exc_value;PyObject* exc_traceback;PyObject* dict;
} PyGreenlet;

每一个greenlet其实就是一个函数,以及保存这个函数执行时的上下文.对于函数来说上下文也就是其stack..同一个进程的所有的greenlets共用一个共同的操作系统分配的用户栈.所以同一时刻只能有栈数据不冲突的greenlet使用这个全局的栈.greenlet是通过stack_stop,stack_start来保存其stack的栈底和栈顶的,如果出现将要执行的greenlet的stack_stop和目前栈中的greenlet重叠的情况,就要把这些重叠的greenlet的栈中数据临时保存到heap中.保存的位置通过stack_copy和stack_saved来记录,以便恢复的时候从heap中拷贝回栈中stack_stop和stack_start的位置.不然就会出现其栈数据会被破坏的情况.所以应用程序创建的这些greenlet就是通过不断的拷贝数据到heap中或者从heap中拷贝到栈中来实现并发的.对于io型的应用程序使用coroutine真的非常舒服.

下面是greenlet的一个简单的栈空间模型(from greenlet.c)

A PyGreenlet is a range of C stack addresses that must be
saved and restored in such a way that the full range of the
stack contains valid data when we switch to it.Stack layout for a greenlet:|     ^^^       ||  older data   ||               |stack_stop . |_______________|.      |               |.      | greenlet data |.      |   in stack    |.    * |_______________| . .  _____________  stack_copy + stack_saved.      |               |     |             |.      |     data      |     |greenlet data|.      |   unrelated   |     |    saved    |.      |      to       |     |   in heap   |stack_start . |     this      | . . |_____________| stack_copy|   greenlet    ||               ||  newer data   ||     vvv       |

下面是一段简单的greenlet代码.

from greenlet import greenletdef test1():print 12gr2.switch()print 34def test2():print 56gr1.switch()print 78gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

目前所讨论的协程,一般是编程语言提供支持的。目前我所知提供协程支持的语言包括python,lua,go,erlang, scala和rust。协程不同于线程的地方在于协程不是操作系统进行切换,而是由程序员编码进行切换的,也就是说切换是由程序员控制的,这样就没有了线程所谓的安全问题。

所有的协程都共享整个进程的上下文,这样协程间的交换也非常方便。

相对于第二种方案(I/O多路复用),使得使用协程写的程序将更加的直观,而不是将一个完整的流程拆分成多个管理的事件处理。

协程的缺点可能是无法利用多核优势,不过,这个可以通过协程+进程的方式来解决。

协程可以用来处理并发来提高性能,也可以用来实现状态机来简化编程。我用的更多的是第二个。去年年底接触python,了解到了python的协程概念,后来通过pycon china2011接触到处理yield,greenlet也是一个协程方案,而且在我看来是更可用的一个方案,特别是用来处理状态机。

目前这一块已经基本完成,后面抽时间总结一下。

总结一下:
1)多进程能够利用多核优势,但是进程间通信比较麻烦,另外,进程数目的增加会使性能下降,进程切换的成本较高。程序流程复杂度相对I/O多路复用要低。
2)I/O多路复用是在一个进程内部处理多个逻辑流程,不用进行进程切换,性能较高,另外流程间共享信息简单。但是无法利用多核优势,另外,程序流程被事件处理切割成一个个小块,程序比较复杂,难于理解。
3)线程运行在一个进程内部,由操作系统调度,切换成本较低,另外,他们共享进程的虚拟地址空间,线程间共享信息简单。但是线程安全问题导致线程学习曲线陡峭,而且易出错。
4)协程有编程语言提供,由程序员控制进行切换,所以没有线程安全问题,可以用来处理状态机,并发请求等。但是无法利用多核优势。
上面的四种方案可以配合使用,我比较看好的是进程+协程的模式。

转载自:http://blog.csdn.net/offbye/article/details/39368781

转载于:https://blog.51cto.com/3922078/1662884

python greenlet背景介绍与实现机制相关推荐

  1. 什么是 Python 的 「内存管理机制」?

    什么是内存管理器(what) Python作为一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言,与大多数编程语言不同,Python中的变量无需事先申明,变量无需指定类型,程序员无需关心内存 ...

  2. 详解 Python 源码之对象机制

    在Python中,对象就是在堆上申请的结构体,对象不能是被静态初始化的,并且也不能是在栈空间上生存的.唯一的例外就是类型对象(type object),Python中所有的类型对象都是被静态初始化的. ...

  3. 深入对比数据科学工具箱:Python和R的异常处理机制

    概述 异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件).Python和R作为一门编程语言自然也是有各自的异常处理机制的,异常 ...

  4. python 递归函数与循环的区别_提升Python效率之使用循环机制代替递归函数

    斐波那契数列 当年,典型的递归题目,斐波那契数列还记得吗? def fib(n): if n==1 or n==2: return 1 else: return fib(n-1)+fib(n-2) 当 ...

  5. python函数参数传递机制_Python 学习笔记(一) 理解Python的函数传参机制

    对于刚接触Python不久的新手,Python的函数传参机制往往会让人迷惑.学过C的同学都知道函数参数可以传值或者传地址.比如下面这段代码 点击(此处)折叠或打开 void func(int inpu ...

  6. Python学习:垃圾回收机制

    Python 程序在运行的时候,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量:计算完成后,再将结果输出到永久性存储器中.如果数据量过大,内存空间管理不善就很容易出现 OOM(out of ...

  7. Python中的字符串驻留机制

    字符串驻留机制(引用计数机制): 字符串驻留是一种在内存中仅保存一份相同且不可变字符串的方法. 系统维护interned字典,记录已被驻留的字符串对象. 对于短字符串,将其赋值给多个不同的对象时,内存 ...

  8. 【Python核心】垃圾回收机制

    Python程序在运行的时候,需要在内存中开辟出一块空间用于存放运行时产生的临时变量,计算完成后再将结果输出到永久性存储器中 如果数据量过大,内存空间管理不善就很容易出现OOM(out of memo ...

  9. python中生成器的惰性机制

    生成器有一个惰性机制,只有当你需要的时候才给你(一个个的取),而不是一下字全部给你.可能有些抽象,来一个例子 吧. 普及一个小知识**:一只母鸡并不是生一辈子鸡蛋,有一个时间段.** 例:小明和小红两 ...

  10. python中的name mangle机制

    #测试python中的name mangle机制class A:__attr1=1 #私有 类属性def __init__(self):self.attr2=2 #私有 对象属性@classmetho ...

最新文章

  1. java runnable 启动_Java开发笔记(九十七)利用Runnable启动线程
  2. python的快速入门-Python快速入门,你想要的就在这里了!
  3. 给一份Webservice接口通用实现!!
  4. 介绍Visual Studio的Android模拟器
  5. 微信二维码支付快速入门
  6. wavecn 2.0.0.5 正式版_微信7.0.5怎么更新?微信7.0.5安卓版下载与更新升级教程
  7. 思科认证网络工程师CCNA(更新完毕)
  8. ModelAndView介绍
  9. Linux MISC 驱动实验
  10. 扩展Windows Mobile模拟器存储空间的方法
  11. SQL Server执行计划那些事儿(3)——书签查找
  12. 安全测试===sqlmap(零)转载
  13. 2018年中国AI行业研究报告
  14. 云服务器 ECS > 块存储 > 块存储介绍 > 块存储概述 请输入关键词
  15. 打通语言理论和统计 NLP 两个世界,Transformers/GNNs 架构能做到吗?
  16. EasyUI - Layout 布局控件
  17. 三菱PLC-信捷人机通信(编程)
  18. vux2.9版本bug
  19. 雷达原理(第五版)常见公式
  20. Chrome浏览器无法访问网页(移动硬盘)

热门文章

  1. main:处理命令行选项
  2. 通过shell进行数学计算
  3. 有关css3的一些问题
  4. 第四次作业-测试作业
  5. RAD Studio 2010 环境设置(转)
  6. Git 和 SVN之间的五个基本区别
  7. 简单的字段类型定义(新新手看)
  8. 游戏玩家的图形显示设置指南(12)(The Gamer's Graphics Display Settings Guide)
  9. Chrome Frame
  10. Linux操作系统 和 Windows操作系统 的区别