python下协程实现原理与greenlet源码解析

本文探讨了Python协程扩展greenlet的工作原理,特别是它如何在Python虚拟机上模拟进程和线程。greenlet的实现涉及到Python的PyFrameObject、PyInterpreterState和PyThreadState等关键结构体。文章详细分析了greenlet的基本执行单元Task的创建与初始化,并解释了在greenlet之间的切换过程,涉及到的slp_switch函数在Python解释器中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

greenlet是一个高效的python协程扩展,与libtask不同,由于greenlet是跑在 python虚拟机上的,而python虚拟机在操作系统上模拟了进程,线程与栈帧结构, 所以greenlet协程在做切换时必须同时切换python虚拟机的栈帧与操作系统进程 的栈帧.而这也是greenlet实现比较tricky的地方,要搞清楚greenlet的具体实 现机制,必须先搞清楚python的三个重要结构体:

PyFrameObject PyInterpreterState PyThreadState

先来看看PyFrameObject:

    typedef struct _frame {
        // PyFrameObject就是python虚拟机的栈帧结构,
        // 也就是一段python的执行代码片,包括:
        // 指向前一个栈帧的指针, 执行代码片地址,builtins dict, globals dict, locals dict
        // 指向最后一个local地址的指针,指向栈顶地址的指针, 代码片所在线程的指针, 第一个local地址的指针

        PyObject_VAR_HEAD
        // f_back指向调用者的栈帧
        struct _frame *f_back;	/* previous frame, or NULL */
        // 执行代码片
        PyCodeObject *f_code;	/* code segment */
        PyObject *f_builtins;	/* builtin symbol table (PyDictObject) */
        PyObject *f_globals;	/* global symbol table (PyDictObject) */
        PyObject *f_locals;		/* local symbol table (any mapping) */
        // f_valuestack指向最后一个local地址
        PyObject **f_valuestack;	/* points after the last local */
        /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
           Frame evaluation usually NULLs it, but a frame that yields sets it
           to the current stack top. */
        // f_stacktop指向栈顶, 当线程初始化时,f_stacktop和f_valuestack指向相同地址
        PyObject **f_stacktop;
        PyObject *f_trace;		/* Trace function */

        /* If an exception is raised in this frame, the next three are used to
         * record the exception info (if any) originally in the thread state.  See
         * comments before set_exc_info() -- it's not obvious.
         * Invariant:  if _type is NULL, then so are _value and _traceback.
         * Desired invariant:  all three are NULL, or all three are non-NULL.  That
         * one isn't currently true, but "should be".
         */
        PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;

        PyThreadState *f_tstate;
        int f_lasti;		/* Last instruction if called */
        /* Call PyFrame_GetLineNumber() instead of reading this field
           directly.  As of 2.3 f_lineno is only valid when tracing is
           active (i.e. when f_trace is set).  At other times we use
           PyCode_Addr2Line to calculate the line from the current
           bytecode index. */
        int f_lineno;		/* Current line number */
        int f_iblock;		/* index in f_blockstack */
        PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_abctee123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值