【问题标题】:What is the stack used for in CPython, if anything?如果有的话,CPython 中使用的堆栈是什么?
【发布时间】:2020-09-26 20:48:36
【问题描述】:

据我所知:

  • 创建线程时每个系统级线程的操作系统内核(例如 Linux)总是 allocates a stack
  • CPython 以其对象使用 private heap 而闻名,其中可能包括用于 Python 子例程的 call stack

如果有,CPython 中使用的堆栈是什么?

【问题讨论】:

    标签: memory-management kernel cpython


    【解决方案1】:

    CPython 是一个普通的C 程序。运行 Python 脚本/模块/REPL/任何东西没有什么神奇之处:必须在循环中读取、解析、解释每段代码,直到完成。每个 Python 表达式和语句背后都有一大堆处理器指令。

    每个“简单”的顶级事物(字节码的解析和生成、GIL 管理、属性查找、控制台 I/O 等)在底层都非常复杂。如果由函数组成,调用其他函数,调用其他函数......这意味着涉及堆栈。说真的,check it你自己:一些源文件跨越几千行代码。

    到达解释器的主循环本身就是一次冒险。以下是从代码库各处拼凑而成的要点:

    #ifdef MS_WINDOWS
    int wmain(int argc, wchar_t **argv)
    {
        return Py_Main(argc, argv);
    }
    #else
    // standard C entry point
    #endif
    
    int Py_Main(int argc, wchar_t **argv)
    {
        _PyArgv args = /* ... */;
        return pymain_main(&args);
    }
    
    static int pymain_main(_PyArgv *args)
    {
        // ... calling some initialization routines and checking for errors ...
        return Py_RunMain();
    }
    
    int Py_RunMain(void)
    {
        int exitcode = 0;
        pymain_run_python(&exitcode);
        // ... clean-up ...
        return exitcode;
    }
    
    static void pymain_run_python(int *exitcode)
    {
        // ... initializing interpreter state and startup config ...
        // ... determining main import path ...
        if (config->run_command) {
            *exitcode = pymain_run_command(config->run_command, &cf);
        }
        else if (config->run_module) {
            *exitcode = pymain_run_module(config->run_module, 1);
        }
        else if (main_importer_path != NULL) {
            *exitcode = pymain_run_module(L"__main__", 0);
        }
        else if (config->run_filename != NULL) {
            *exitcode = pymain_run_file(config, &cf);
        }
        else {
            *exitcode = pymain_run_stdin(config, &cf);
        }
        // ... clean-up
    }
    
    int PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags)
    {
        // ... even more routing ...
        int err = PyRun_InteractiveLoopFlags(fp, filename, flags);
        // ...
    }
    
    int PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags *flags)
    {
        // ... more initializing ...
        do {
            ret = PyRun_InteractiveOneObjectEx(fp, filename, flags);
            // ... error handling ...
        } while (ret != E_EOF);
        // ...
    }
    

    【讨论】:

    • 知道了,因为 CPython 使用 私有堆 存储 Python 对象,跨 Python 函数调用的数据结构,当然,这并不排除 CPython 使用操作系统为这些 C 调用提供的堆栈,对吗?
    • @Josh Python 脚本运行在 CPython(解释器)之上,而 CPython 运行在 CPU 之上。 CPython 不能在自身之上/在它自己的 Python 堆栈上运行,因为这些堆栈不兼容,它们使用不同的数据结构——一个由 C 定义,另一个由 CPython 定义。
    • 另外,CPython 使用操作系统提供的堆栈不是因为它可以,而是因为它必须这样做。通过什么方式提供堆栈并不重要。我的意思是,理论上可以编写不使用堆栈的 C 程序,但这将是受虐狂的可怕练习。
    猜你喜欢
    • 1970-01-01
    • 2014-10-16
    • 2020-10-24
    • 2015-12-29
    • 2019-07-24
    • 2021-05-10
    • 2012-04-21
    • 2014-08-09
    • 1970-01-01
    相关资源
    最近更新 更多