当前位置:Gxlcms > Python > pythongreenlet实现机制

pythongreenlet实现机制

时间:2021-07-01 10:21:17 帮助过:68人阅读

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

  1. typedef struct _greenlet {
  2. PyObject_HEAD
  3. char* stack_start;
  4. char* stack_stop;
  5. char* stack_copy;
  6. intptr_t stack_saved;
  7. struct _greenlet* stack_prev;
  8. struct _greenlet* parent;
  9. PyObject* run_info;
  10. struct _frame* top_frame;
  11. int recursion_depth;
  12. PyObject* weakreflist;
  13. PyObject* exc_type;
  14. PyObject* exc_value;
  15. PyObject* exc_traceback;
  16. PyObject* dict;
  17. } 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)

  1. A PyGreenlet is a range of C stack addresses that must be
  2. saved and restored in such a way that the full range of the
  3. stack contains valid data when we switch to it.
  4. Stack layout for a greenlet:
  5. | ^^^ |
  6. | older data |
  7. | |
  8. stack_stop . |_______________|
  9. . | |
  10. . | greenlet data |
  11. . | in stack |
  12. . * |_______________| . . _____________ stack_copy + stack_saved
  13. . | | | |
  14. . | data | |greenlet data|
  15. . | unrelated | | saved |
  16. . | to | | in heap |
  17. stack_start . | this | . . |_____________| stack_copy
  18. | greenlet |
  19. | |
  20. | newer data |
  21. | vvv |

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

  1. from greenlet import greenlet
  2. def test1():
  3. print 12
  4. gr2.switch()
  5. print 34
  6. def test2():
  7. print 56
  8. gr1.switch()
  9. print 78
  10. gr1 = greenlet(test1)
  11. gr2 = greenlet(test2)
  12. gr1.switch()

人气教程排行