Python C-Api 线程问题

2024-05-03

我正在编写一个 C 程序,它使用用 python 编写的网络库。我将 python lib 与 python C api 一起嵌入。该库异步发送所有请求,并在请求完成时通过信号通知我。

这意味着理论上。

实际上我有两个与线程相关的问题:

  1. 从 c 对 python lib 的所有调用都是块状的(它们应该立即返回)
  2. python lib 异步调用已注册的回调 (thread.start_new_thread(callback, args))。这不起作用(什么也没有发生)。如果我将 python 代码更改为回调(args),那么它就可以工作。

我做错了什么?我需要做些什么才能使多线程工作吗?


我有类似的情况。

初始工作流程

  1. 应用程序从C++层开始
  2. C++层在主线程调用Python层的函数
  3. 主线程中的Python层函数创建事件线程
  4. 在Python层启动事件线程并返回C++层
  5. 主循环在C++层开始
  6. 如果需要,事件线程调用C++层的回调函数

从一开始,事件线程就以意想不到的方式工作。从我遇到的情况来看,我猜这是由于GIL造成的,所以我尝试从GIL解决这个问题。这是我的解决方案。

Analysis

首先,从注释中PyEval_InitThreads https://docs.python.org/2/c-api/init.html#c.PyEval_InitThreads,

当只有主线程存在时,不需要GIL操作。 ...因此,最初并没有创建锁。 ...

所以如果需要多线程,PyEval_InitThreads()必须在主线程中调用。我打电话PyEval_InitThreads() before Py_Initialize()。现在GIL已初始化并且主线程获取GIL。

其次,每次从 C++ 层调用 Python 函数之前,PyGILState_Ensure()被调用以获取GIL。另外,调用Python函数后,PyGILState_Release(state)被调用返回到之前的 GIL 状态。结果,在步骤2之前,PyGILState_Ensure()被调用,并且在步骤 4 之后,PyGILState_Release(state)叫做。

但有一个问题。从PyGILState_Ensure https://docs.python.org/2/c-api/init.html#c.PyGILState_Ensure and PyGILState_Release https://docs.python.org/2/c-api/init.html#c.PyGILState_Release,这两个函数分别是保存当前的GIL状态来获取GIL和恢复之前的GIL状态来释放GIL。然而,打电话后PyEval_InitThreads()在主线程中,主线程肯定拥有GIL。主线程中的GIL状态如下:

/* main thread owns GIL by PyEval_InitThreads */

state = PyGILState_Ensure();
/* main thread owns GIL by PyGILState_Ensure */

...
/* invoke Python function */
...

PyGILState_Release(state);
/* main thread owns GIL due to go back to previous state */

从上面的代码示例中,主线程始终拥有 GIL,因此事件线程永远不会运行。为了克服这种情况,让主线程在调用之前不获取GILPyGILState_Ensure()。因此,调用后PyGILState_Release(state),主线程可以释放GIL让事件线程运行。因此,当GIL初始化时,应立即在主线程中释放GIL。

Here PyEval_SaveThread()用来。从PyEval_SaveThread https://docs.python.org/2/c-api/init.html#c.PyEval_SaveThread,

释放全局解释器锁(如果已创建并且启用了线程支持)并将线程状态重置为 NULL,...

这样,Python 就可以嵌入多线程了。

修改后的工作流程

  1. 应用程序从C++层开始
  2. PyEval_InitThreads();启用多线程
  3. save = PyEval_SaveThread();在主线程中释放GIL
  4. state = PyGILState_Ensure();在主线程中获取GIL
  5. C++层在主线程调用Python层的函数
  6. 主线程中的Python层函数创建事件线程
  7. 在Python层启动事件线程并返回C++层
  8. PyGILState_Release(state);在主线程中释放GIL
  9. 主循环在C++层开始
  10. 如果需要,事件线程调用C++层的回调函数
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python C-Api 线程问题 的相关文章

  • 将 saxon 与 python 结合使用

    我需要使用 python 处理 XSLT 目前我正在使用仅支持 XSLT 1 的 lxml 现在我需要处理 XSLT 2 有没有办法将 saxon XSLT 处理器与 python 一起使用 有两种可能的方法 设置一个 HTTP 服务 接受
  • 将数据从 python pandas 数据框导出或写入 MS Access 表

    我正在尝试将数据从 python pandas 数据框导出到现有的 MS Access 表 我想用已更新的数据替换 MS Access 表 在 python 中 我尝试使用 pandas to sql 但收到错误消息 我觉得很奇怪 使用 p
  • 通过最小元素比较对 5 个元素进行排序

    我必须在 python 中使用元素之间的最小比较次数来建模对 5 个元素的列表进行排序的执行计划 除此之外 复杂性是无关紧要的 结果是一个对的列表 表示在另一时间对列表进行排序所需的比较 我知道有一种算法可以通过 7 次比较 总是在元素之间
  • 使用带有关键字参数的 map() 函数

    这是我尝试使用的循环map功能于 volume ids 1 2 3 4 5 ip 172 12 13 122 for volume id in volume ids my function volume id ip ip 我有办法做到这一点
  • 从字符串中删除识别的日期

    作为输入 我有几个包含不同格式日期的字符串 例如 彼得在16 45 我的生日是1990年7月8日 On 7 月 11 日星期六我会回家 I use dateutil parser parse识别字符串中的日期 在下一步中 我想从字符串中删除
  • python 相当于 R 中的 get() (= 使用字符串检索符号的值)

    在 R 中 get s 函数检索名称存储在字符变量 向量 中的符号的值s e g X lt 10 r lt XVI s lt substr r 1 1 X get s 10 取罗马数字的第一个符号r并将其转换为其等效整数 尽管花了一些时间翻
  • 基于代理的模拟:性能问题:Python vs NetLogo & Repast

    我正在 Python 3 中复制一小段 Sugarscape 代理模拟模型 我发现我的代码的性能比 NetLogo 慢约 3 倍 这可能是我的代码的问题 还是Python的固有限制 显然 这只是代码的一个片段 但 Python 却花费了三分
  • OpenCV 无法从 MacBook Pro iSight 捕获

    几天后 我无法再从 opencv 应用程序内部打开我的 iSight 相机 cap cv2 VideoCapture 0 返回 并且cap isOpened 回报true 然而 cap grab 刚刚返回false 有任何想法吗 示例代码
  • AWS EMR Spark Python 日志记录

    我正在 AWS EMR 上运行一个非常简单的 Spark 作业 但似乎无法从我的脚本中获取任何日志输出 我尝试过打印到 stderr from pyspark import SparkContext import sys if name m
  • 绘制方程

    我正在尝试创建一个函数 它将绘制我告诉它的任何公式 import numpy as np import matplotlib pyplot as plt def graph formula x range x np array x rang
  • 从 Flask 访问 Heroku 变量

    我已经使用以下命令在 Heroku 配置中设置了数据库变量 heroku config add server xxx xxx xxx xxx heroku config add user userName heroku config add
  • BeautifulSoup 中的嵌套标签 - Python

    我在网站和 stackoverflow 上查看了许多示例 但找不到解决我的问题的通用解决方案 我正在处理一个非常混乱的网站 我想抓取一些数据 标记看起来像这样 table tbody tr tr tr td td td table tr t
  • 在Python中获取文件描述符的位置

    比如说 我有一个原始数字文件描述符 我需要根据它获取文件中的当前位置 import os psutil some code that works with file lp lib open path to file p psutil Pro
  • IO 密集型任务中的 Python 多线程

    建议仅在 IO 密集型任务中使用 Python 多线程 因为 Python 有一个全局解释器锁 GIL 只允许一个线程持有 Python 解释器的控制权 然而 多线程对于 IO 密集型操作有意义吗 https stackoverflow c
  • Pandas:merge_asof() 对多行求和/不重复

    我正在处理两个数据集 每个数据集具有不同的关联日期 我想合并它们 但因为日期不完全匹配 我相信merge asof 是最好的方法 然而 有两件事发生merge asof 不理想的 数字重复 数字丢失 以下代码是一个示例 df a pd Da
  • 如何在 Python 中追加到 JSON 文件?

    我有一个 JSON 文件 其中包含 67790 1 kwh 319 4 现在我创建一个字典a dict我需要将其附加到 JSON 文件中 我尝试了这段代码 with open DATA FILENAME a as f json obj js
  • 类型错误:预期单个张量时的张量列表 - 将 const 与 tf.random_normal 一起使用时

    我有以下 TensorFlow 代码 tf constant tf random normal time step batch size 1 1 我正进入 状态TypeError List of Tensors when single Te
  • 使用 Python 绘制 2D 核密度估计

    I would like to plot a 2D kernel density estimation I find the seaborn package very useful here However after searching
  • Scrapy:如何使用元在方法之间传递项目

    我是 scrapy 和 python 的新手 我试图将 parse quotes 中的项目 item author 传递给下一个解析方法 parse bio 我尝试了 request meta 和 response meta 方法 如 sc
  • Python Selenium:如何在文本文件中打印网站上的值?

    我正在尝试编写一个脚本 该脚本将从 tulsaspca org 网站获取以下 6 个值并将其打印在 txt 文件中 最终输出应该是 905 4896 7105 23194 1004 42000 放置的动物 的 HTML span class

随机推荐