单个进程、多个解释器、无 GIL 竞争 - Python3.12 之前

主要观点:作者在 Basis 上工作数月,虽工作时长不同但仍喜欢其框架,将用此空间写机器人等相关内容。探讨如何让 Python 在 Basis 中运行,包括架构、遇到的问题及解决方案等。
关键信息:

  • Basis 架构:将一切加载到同一进程空间,可实现多进程运行“机器人”代码,如感知、规划等,ROS1 可通过 nodelets 实现,ROS2 用“components”,而 Basis 可无协调器运行(仅一个进程时)。
  • Python 在 Basis 中运行的问题:Python(3.12 前)不支持在一个进程中作为多个实例运行,会导致运行时冲突,且多线程时会出现各种问题,如pthread_getspecific返回值不同等。
    解决方案:
  • 使用dlmopen创建新的符号命名空间来加载 Python,避免共享符号,但仍存在一些问题,如static变量导致的全局日志格式化问题等。
  • 注入pthread部分的glibc到命名空间的 Python 中,使 Python 线程使用主进程的pthread实现,可安全地在主进程初始化多个 Python 实例。
  • 解决import numpy时的 locale 问题,实现自己的非 TLS 版本的相关函数。
  • 调试模块时,需获取模块在/proc/<proc>/maps中的基地址,通过target modules addtarget modules load关联符号与地址。
  • 安全地从其他线程调用 Python 代码,需在主线程调用PyThreadState *main_tstate = PyEval_SaveThread();,并在调用 Python API 时使用PyGILState_Ensure()PyGILState_Release()
  • 用 X 宏自动为符号创建函数指针,实现透明地调用 Python API。
  • 不推荐自行这样做,调试困难,glibc 仅支持 16 个命名空间,作者将清理代码并提交 PR,后续可能使用 Python3.12 子解释器。

重要细节:作者不是 Python 或 Linux 专家,所做仅为实验和分享,代码中有多处注释说明问题及解决方案,如各种函数的作用、遇到的错误及尝试的解决方法等。

阅读 10
0 条评论