我有一个来自 SWIG 包装的 C++ 库的类的实例,我想从中提取其引用,以便能够在 Cython 文件中使用它,在该文件中,我通过使用直接链接到同一个 C++ 库更轻量级的自制 Cython 同类包装器。
我知道这不会像访问某些隐藏属性那么容易,但我想 SWIG 或 CPython 中可能有一些函数,如果从 Cython 中链接到它(也许是某些 PyObject_*?),可能会这样做。
不幸的是,我对 SWIG 或 CPython 内部的了解不够,无法知道如何做到这一点,或者在不修改 SWIG 绑定的源代码的情况下这是否真的可行。
我正在和一个朋友聊天,比较语言,他提到 Java 的自动内存管理优于 Python,因为 Java 的压缩,而 Python 则没有——因此对于长时间运行的服务器,Python 是一个糟糕的选择。
没有进入哪个更好或更坏,他的说法是否正确 - CPython 的垃圾收集器是否不会压缩内存,因此,长时间运行的 Python 进程是否会随着时间的推移变得越来越碎片化?
我知道运行 CPython 的垃圾收集器是可选的。大多数情况下,它使用自动引用计数进行自动内存管理,一旦引用计数达到零,对象就会被释放——因此,就释放对象而言,CPython 的垃圾收集器唯一需要做的就是检测没有根集中的对象有一个引用。但我不知道除此之外它是否进行任何压缩的细节。
如果没有,那么长时间运行的 CPython 进程如何解决内存碎片问题?
我foo在 Python 扩展模块中有一个函数,它应该向 Python 返回一个整数元组。这可以使用Py_BuildValue以下方法轻松完成:
static PyObject*
foo(PyObject* self, PyObject* args)
{
int a = 0;
int b = 0;
/* calculations and stuff */
PyObject* out = Py_BuildValue("(iii)", a, b, a+b);
Py_INCREF(out);
return out;
}
Run Code Online (Sandbox Code Playgroud)
而不是Py_BuildValue,我想使用PyTuple_Pack,它确保返回值确实是一个元组。
在Python的C API文档说,PyTuple_Pack(3, a, b, a+b)相当于Py_BuildValue("(iii)", a, b, a+b)。这两个函数都返回一个新的类型引用PyPbject*。
因此,鉴于上面的代码,
static PyObject*
foo(PyObject* self, PyObject* args)
{
/* ... */
PyObject* out = PyTuple_Pack(3, a, b, a+b);
Py_INCREF(out); …Run Code Online (Sandbox Code Playgroud) 我发现了一些关于 python 如何跟踪locals().
考虑以下脚本:
import gc
class T(object):
pass
def func1():
t = T()
#locals()
del t
#locals()
for o in gc.get_objects():
if type(o) is T:
print("STILL EXISTS")
func1()
Run Code Online (Sandbox Code Playgroud)
运行locals()注释的两个调用(如上)没有给我任何消息,表明T()创建的对象是垃圾收集的。
当我使用第一个locals()命令运行它(删除第一个注释)时,它似乎创建了一个包含对我的t对象的引用的字典。这本词典与任何名字都没有关联,所以我不希望这个 dict 能像没有被垃圾收集一样存在。
问题是,运行代码,我得到"STILL EXISTS". 即使我t从函数命名空间中删除,该对象也不会被垃圾收集,因为返回的 dictlocals()仍在引用它。
有趣的是,如果我locals()再次调用(删除上面代码中的第二条注释),那么字典会以某种方式更新,它不包含t在其中并且对象被成功垃圾收集(并且我没有收到"STILL EXISTS"消息)。
我觉得这种行为有点奇怪。
问题是:
locals()即使没有与任何名称相关联也很长寿命是否正常?编辑:我正在使用 cpython 3.6
谢谢!
使用 CPython2 我可以编译我的 Python 源代码包python.exe -c "import mypackage"。*.py递归删除所有文件后,我可以简单地导入它import mypackage并像往常一样使用它。
使用 CPython3 我可以编译我的 Python 源代码 pyckage python.exe -m compileall -b "full/path/to/mypackage"。*.py递归删除所有文件后,我可以简单地使用import mypackage. 并像往常一样使用它。
这甚至可以以完全相同的方式使用 PyPy3 来完成。
令人惊讶的是,当使用 PyPy2 时,这不起作用!
编译和删除源文件后,我得到以下输出:
Python 2.7.13 (9112c8071614, Feb 06 2019, 23:10:08)
[PyPy 7.0.0 with MSC v.1500 32 bit] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>> import mypackage
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: …Run Code Online (Sandbox Code Playgroud) CPython 中如何实现frozenset 相等?特别是,我想知道 fronzenset 中的各个元素如何相互比较以及它们的总时间复杂度。
我查看了set 和frozenset 在实现和/sf/answers/3624485581/ 中的差异。
第二个链接中的答案涵盖了比较集合中各个元素之前的步骤,但缺少实际的比较算法。
如果我在 Windows 上从源代码构建 CPython,当我想要 pip 安装包含 C 扩展的包时,我会遇到问题。链接库时似乎发生了错误。
例如,安装 cython 时(但在其他 C 扩展包上也会崩溃并出现相同的错误):
链接:致命错误 LNK1104:无法打开文件“python38.lib”
错误:命令“C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.23.28105\bin\HostX86\x86\link.exe”失败,退出状态为 1104
之所以无法打开“python38.lib”,是因为调试模式下的“.lib”文件名为“python38_d.lib”。
一个最小的可重现示例(在命令行上)基于CPython 开发人员指南的快速参考:
git clone --branch v3.8.0 https://github.com/python/cpython.git
cd cpython
git checkout v3.8.0
.\PCbuild\build.bat -e -d
.\PCbuild\win32\python_d.exe -m ensurepip
.\PCbuild\win32\python_d.exe -m pip install pip --upgrade -vv
.\PCbuild\win32\python_d.exe -m pip install setuptools --upgrade -vv
.\PCbuild\win32\python_d.exe -m pip install cython -vv
Run Code Online (Sandbox Code Playgroud)
结果distutils.sysconfig.get_config_vars()是:
{'BINDIR': '...\\cpython\\PCbuild\\win32',
'BINLIBDEST': ...\\cpython\\Lib',
'EXE': '.exe',
'EXT_SUFFIX': '_d.cp38-win32.pyd',
'INCLUDEPY': '...\\cpython\\include;...\\cpython\\PC',
'LIBDEST': '...\\cpython\\Lib',
'SO': '_d.cp38-win32.pyd',
'VERSION': …Run Code Online (Sandbox Code Playgroud) 下面的代码在 Python 中是如何工作的:
a = input()
b = input()
a, b = b, a # STATEMENT 1
print(a, b)
Run Code Online (Sandbox Code Playgroud)
语句 1 是否在 Python 堆内存空间中创建第三个变量来交换两个数字,或者是否使用某种算法来进行交换?
Java 和 python(仅讨论 CPython)分别被解释为 Java 和 CPython 字节码。然后,这两个字节码都由它们各自的虚拟机(JVM 和 Cpython VM)解释。(这里我忽略了在 10K 运行后开始的 JIT 编译部分。)
我对此有两个问题:
虽然它在运行时扮演着重要的角色,但我认为静态和动态类型在编译过程中不应该扮演太大的角色,也不应该是造成这种时间差异的唯一原因。另外,我认为在这两个实现中,在字节码生成期间进行了一些优化。
有什么我在这里想念的吗?(我没有太多的 Java 工作经验。)
更新:
我实际上对 python 第一次运行和后来的运行做了时间分析,发现语句 2 是错误的。运行大型python文件时有非常明显的区别。
方法很简单。创建了一个包含重复行的大文件
a = 5
b = 6
c = a*b
print(str(c))
Run Code Online (Sandbox Code Playgroud)
然后将其导入文件large.py并运行time python large.py
首次运行结果:
python large.py 1.49s user 0.33s system 97% cpu 1.868 total
Run Code Online (Sandbox Code Playgroud)
第二次运行结果:
python large.py 0.20s user 0.08s system …Run Code Online (Sandbox Code Playgroud) 我有一个Windows fatal exception: code 0xc0000374- 是的,有多重处理(等待但是......)。Google 表示异常代码 0xc0000374 表示堆损坏。是的,多处理是必须具备的。它是我正在使用的框架的一部分,因为每个机器人都有可能拥有自己的核心来运行。TL;DR 我无法改变存在多处理的事实。但是,我的机器人仅在一个线程上运行,因此实际上应该不会出现问题,而且事实上,这个问题相对较新。
我想我已经找到了问题所在,但这并没有多大意义。我正在用 C 扩展 Python,以缩短运行时间,我认为这就是错误所在。我已将其范围缩小到一个名为 的函数ground_shot_is_viable,因为当我在 Python 中注释掉它时,错误永远不会发生。然而,当我尝试打印垃圾邮件时(在这种情况下,我实际上写入了一个文件,因为这更适合数百次打印),我发现该功能成功完成。我认为错误在于该函数超出了它的内存边界,这会损坏部分数据,导致崩溃回溯指向其他地方。(在这种情况下,这是我正在使用的框架中的一个无辜的行 -File "G:\RLBotGUIX\venv\lib\site-packages\rlbot\utils\rendering\rendering_manager.py", line 104 in end_rendering它将变量设置为False)
我还对其他功能进行了测试,由于某种原因它们不会导致此问题。有一个很小很小的潜力,因为他们没有像 那样频繁地被调用ground_shot_is_viable。
该错误仅在几分钟后发生,概率总计至少几百次,也许一千次。(机器人的运行速度高达 120tps,因此该函数有可能每秒被调用 120 次。)
我只能通过将环境变量 PYTHONFAULTHANLDER 设置为 1 来获得回溯 - 当我没有这样做时,我的程序只是默默地崩溃了。
当我使用 python.exe 启动程序时,我也没有得到故障转储,但使用 pythonw.exe 确实得到了故障转储。
追溯:
Windows fatal exception: code 0xc0000374
Thread 0x00008004 (most recent call first):
File "G:\RLBotGUIX\Python37\lib\threading.py", line 296 in wait
File "G:\RLBotGUIX\Python37\lib\multiprocessing\queues.py", line 224 in _feed
File "G:\RLBotGUIX\Python37\lib\threading.py", line 870 in …Run Code Online (Sandbox Code Playgroud) cpython ×10
python ×10
python-3.x ×2
algorithm ×1
c ×1
c++ ×1
compilation ×1
cython ×1
frozenset ×1
java ×1
jvm ×1
pip ×1
pypy ×1
python-c-api ×1
setuptools ×1
swap ×1
swig ×1