基准

为了掌握Pymunk的实际性能,此页面包含了许多基准测试。

所有基准测试的完整代码可在 benchmarks 文件夹。

请注意,Pymunk6.0的基准测试还没有更新,但测试看起来很有希望。

获取和回调

为了在最常见的情况下衡量Pymunk造成的开销,我创建了两个微基准。它们应该显示实际包装代码的速度,这可以告诉Pymunk产生了多大的开销,以及不同的包装方法有多大的差异。

使用Pymunk的典型程序最常见的操作是从Pymunk对象中读出位置和角度。通常会在模拟中的每个对象的每一帧中执行此操作,因此这是决定操作速度的一个重要因素。

鉴于此,我们的第一个测试是:

t += b.position.x + b.position.y + b.angle

(见 pymunk-get.py )

运行它很简单,例如,对于Pymunk 4.0::

> python -m pip install pymunk==4.0
> python pymunk-get.py

我们所做的第二个测试是基于我们可以做的第二件重要事情,即使用回调,例如作为冲突处理程序或位置函数:

def f(b,dt):
    b.position += (1,0)

s.step(0.01)

(见 pymunk-callback.py )

结果:

测试在搭载英特尔i7-4600U的惠普G1 1040笔记本电脑上运行。笔记本电脑运行Windows,测试在运行64位Debian的VirtualBox VM中运行。CPython测试使用来自Conda的CPython,而PyPy测试使用手动下载的PyPy。CPython2.7使用CFFI 1.7,其他测试使用CFFI 1.8。

请记住,这些结果并不能告诉您游戏/应用程序将如何运行,它们可以更多地被视为有助于识别性能问题和了解Python之间的区别。

Pymunk-Get:

CPython2.7.12

CPython3.5.2

PyPy 5.4.1

Pymunk5.1

2.1s

2.2s

0.36s

Pymunk5.0

4.3s

4.5s

0.37s

Pymunk4.0

1.0s

0.9s

0.52s

Pymunk-回调:

CPython2.7.12

CPython3.5.2

PyPy 5.4.1

Pymunk5.1

5.7s

6.8s

1.1s

Pymunk5.0

6.5s

7.3s

1.0s

Pymunk4.0

5.1s

6.5s

4.5s

从这些结果中我们可以看到,如果有可能,您应该使用PyPy,因为它比常规的CPython快得多。我们还可以看到,在Pymunk 4和5之间从Ctype迁移到CFFI在CPython中有负面影响,但对PyPy有积极影响,而Pymunk 5和PyPy一起使用是最快的选择。

速度在5.0到5.1之间的提升是因为Vec2d类及其在Pymunk中的内部处理方式被更改以提高性能。

批处理API

Pymunk 6.6.0引入了一个新的实验性批处理API,可以在批处理中高效地检索车身和碰撞数据,这些批处理经过优化,可以进一步高效地处理,例如使用NumPy。

为了测试这一点,有一个新的基准测试,它将获取位置和角度(Batch API的几乎每个用户都会使用的数据)正常地与新的API进行比较。该基准测试使用不同数量的主体运行,并将迭代次数调整为在合理时间内完成。

(见 pymunk-batch-api.py )

基准测试是使用内部预发布的Pymunk 6.6.0运行在Windows上,在ThinkPad X1 Carbon 7 Gen上使用CPython3.11和PyPy 3.10-v7.3.12。

结果:

下面我们可以看到,在一个空间中使用5个实体时,使用批处理API的速度已经更快了,如果使用CPython,它处理大量实体的速度大约是普通非批处理API的40倍。有了PyPy,改进要温和得多。

身体

正常API

批处理API

正常的PyPy

批处理PYPy

1

2.2s

4.2s

0.4s

0.5s

5

2.0s

0.8s

0.3s

0.3s

10

2.1s

0.4s

0.3s

0.2s

100

2.2s

0.09s

0.3s

0.2s

1000

2.3s

0.05s

0.3s

0.2s

10000

不适用

0.04s

不适用

0.2s

50000

不适用

0.06s

不适用

0.2s

100000

不适用

0.07s

不适用

0.2s

得到的时间是获得位置和角度数据的时间除以物体数量的1000000倍。

由此我们可以看出,如果只有1个Body,那么使用普通API的速度是使用CPython的批处理API的两倍。然而,在5个主体中,批处理API的速度是普通API的(超过)两倍。这比预期的要好,也显示了潜力。

对于更多的主体,很明显,正常API的运行时或多或少是线性扩展的,这意味着无论主体的数量如何,获取单个主体的开销都是恒定的。对于批处理API,我们可以看到批处理有很高的开销,当我们达到大约1000个主体时,它开始像普通API一样扩展,每个主体的开销或多或少是恒定的。我们还可以看到,每个身体的时间略有增加,可能是因为收集结果所需的更大的阵列,或者是Chipmunk内部的一些其他开销。

另一方面,对于PyPy来说,结果就不那么令人兴奋了。使用普通API的PyPy已经非常快了,如 Pymunk-Get 基准测试,并且使用批处理API只提供了适度的改进。

与其他物理类库相比

备注

到目前为止(2023年),西蒙克(也是pybox2d)似乎没有得到维护。

西蒙克

Cymunk 是Chipmunk的另一种包装。与Pymunk不同,它使用Cython进行包装(Pymunk使用CFFI),这为它提供了不同的性能配置文件。然而,由于两者都是围绕Chipmunk建造的,所以总体速度将非常相似,只有当信息从Chipmunk传递/传递到Chipmunk时才会有所不同。这正是微基准测试要衡量的开销类型。

《Pymunk》没有《金龟子》功能齐全,所以为了和《金龟子》相比,我们必须做一些调整。一个主要的区别是,它不实现 position_func 函数,因此我们使用冲突处理程序执行替代回调测试::

h = s.add_default_collision_handler()
def f(arb):
    return false
h.pre_solve = f

s.step(0.01)

(见 pymunk-collision-callback.pycymunk-collision-callback.py )

结果

测试在搭载英特尔i7-4600U的惠普G1 1040笔记本电脑上运行。笔记本电脑运行Windows,测试在运行64位Debian的VirtualBox VM中运行。CPython测试使用来自Conda的CPython,而PyPy测试使用手动下载的PyPy。CFFI版本1.10.0和Cython 0.25.2。

由于Cymunk没有合适的版本,所以我使用了其Github库中最新的主版本,hash 24845cc,检索日期为2017-09-16。

获取:

CPython3.5.3

PYPY 5.8

Pymunk5.3

2.14s

0.33s

《西蒙克20170916》

0.41s

(10秒)

冲突-回调:

CPython3.5.3

PYPY 5.8

Pymunk5.3

3.71s

0.58s

《西蒙克20170916》

0.95s

(7.01秒)

(括号内的Cymunk结果显示在PyPy上,因为众所周知,Cython在PyPy上速度很慢)

从这些结果中我们可以看到,Cymunk在CPython上的速度比在CPython上的Pymunk快得多,但当我们包括PyPy时,Pymunk取得了全面的胜利。

我们没有考虑到的一点是,您可以牺牲便利性来换取性能,并在应用程序代码中使用Cython来加快速度。我认为这就是KivEnt使用的方法,KivEnt是Cymunk的主要用户。然而,由于编译器要求和代码更改,在开发应用程序时需要进行复杂得多的设置。