使用Cython指针序列化不可序列化的Python对象

2024-04-23 14:11:57 发布

您现在位置:Python中文网/ 问答频道 /正文

在过去的4年里,我一直在开发一个Python调试器(断断续续),它在帮助我调试复杂的Python代码方面非常有用。调试器的作用类似于程序跟踪,允许我查看程序执行的所有操作。它通过使用一组print语句来实现这一点。你知道吗

例如,以下Python代码:

if(x == True):
    Trace.If("User has enabled 'x'")

    n = Trace.Variable(n + x + y)

else:
    Trace.Else("User has not enabled anything")

    pass

将以下内容输出到日志文件或数据库(假设满足“if”语句条件):

Counter - Timestamp - Filename - Function - Line of Code - If - User has enabled 'x'
Counter - Timestamp - Filename - Function - Line of Code - Variable - n = 13

旧版本的调试器执行主进程/线程中的每个跟踪操作(与调试器跟踪的程序关联)。虽然这对于不需要计时的应用程序来说不是问题,但是不能正确跟踪的程序。因此,我开始研究Python调试器的多线程版本(大约1年)。尽管从调试库的单线程版本到调试库的多线程版本的速度改进帮助很大(因为我的库中很多都是I/O负载),但对于某些时间关键型Python应用程序来说,这还不够。你知道吗

然后,我开始在调试库的多处理版本上工作(大约0.5年),除了与Python对象分析相关的调试语句外,其他一切都正常工作。例如,以下内容:

n = Trace.Variable(...some Python object...)

。。。将尝试分析Python对象,返回所讨论的Python对象的序列化版本。例如,以下代码:

testABC = Trace.Variable([1, 2, [3, 4, {'Bacon': 0, 'Ham': 1, 'Cheese': 2, 'Eggs': 3456}]])

…将输出以下跟踪/调试数据:

Counter - Timestamp - Filename - Function - Line of Code - Variable - testABC : (list) - [0] : (integer) - 1, [1] : (integer) - 2, [2] : (list) - [2][0] : (integer) - 3, [2][1] : (integer) - 4, [2][2] : (dictionary) - [2][2]{Bacon} : (integer) - 0, [2][2]{Ham} : (integer) - 1, [2][2]{Cheese} : (integer) - 2 and [2][2]{Eggs} : (integer) - 3456

不幸的是,库中处理Python对象分析的部分可能很慢(取决于所分析的Python对象)。为了防止主执行进程/线程的速度减慢,我尝试在一个单独的Python进程中分析Python对象。问题是某些Python对象无法序列化(例如frame或inspect)。你知道吗

我尝试过每种类型的序列化库(如Pickle、Dill等)以及分布式计算库(如ExecNet、RPyC等),但无法将不可序列化的Python对象传递给单独的进程。这是一个问题的原因,是我的Python调试库旨在调试/跟踪所有Python脚本。如果一个脚本碰巧分析了一个不可变量化的Python对象,我需要在主执行进程/线程中执行对该Python对象的分析(如前所述,这可能非常慢)。你知道吗

我已经研究了如何使用Python解释器,它允许我禁用GIL(全局解释器锁),希望在一个单独/并发线程中执行这种代价高昂的分析。Jython或IronPython等解释器目前只支持Python2.7(这是一个问题,因为我的库调试的是Python3.0+脚本)。我还研究了可以加快Python执行速度的解释器(希望降低在主进程/线程中执行代价高昂的分析的成本),比如PyPy,但PyPy的主要问题是它对Windows(以及某种程度上的Python3)的支持似乎很薄弱。另外,为PyPy重新安装所有库的要求也是一个问题(特别是考虑到并非所有Python库都得到完全支持——尽管我相信他们正在努力)。你知道吗

说了这么多,我有最后一个解决办法,我希望尝试。在这样做之前,我希望在编写代码之前先和Stack Overflow论坛上的人讨论一下这个解决方案(因为我不确定它是否可行)。解决方案的伪代码如下:

1. Process 1 - Passes Python object (to be analyzed) to a Cython function.

2. Process 1 - Cython function stores Python object in memory and returns the memory address of the Python object.

3. Process 1 - Passes memory address of Python object (stored by Cython function) to a separate Python process (Process 2).

4. Process 2 - Receives memory address of Python object (stored by Cython function from Process 1) and passes the address to a Cython function.

5. Process 2 - Cython function pulls the Cython object pointing to the memory address, and returns a proxy of the original object.

6. Process 2 - Analyzes the Python object (returned by Cython function).

问题1—这可能吗(假设Python本身不支持通过引用将对象传递给另一个进程)?你知道吗

问题2——如果是这样,那么在我退出Cython函数(从第2步开始)时,Python的垃圾收集器会释放这个对象吗,还是会保留在内存中(假设Cython依赖程序员来释放内存—就像在C中一样)?你知道吗

问题3-步骤5会返回一个Python对象吗,还是我必须将C对象转换成Python对象(如果是这样,我将如何做)?你知道吗

抱歉问了这么长时间。任何帮助都将不胜感激。你知道吗

谢谢你。你知道吗


Tags: ofthe对象代码版本object进程trace