pypy 可能比默认编译器慢的可能原因

con*_*kid -2 python pypy numpy multiprocessing pandas

我正在为学校做这个项目,我应该让脚本运行得更快,因为它非常慢。在过去的几个月里,由于我无法访问实际的脚本,因此我正在测试我编写的虚拟脚本,该脚本执行相同的任务。为此,我发现 pypy 与多处理一起使我的脚本运行速度至少提高了 10 倍。因此,在访问实际脚本后,我对其应用了多重处理并使用 pypy 运行它。然而,令人惊讶的是,与不使用 pypy 相比,使用 pypy 运行的代码运行速度慢了 2 倍,而不是显示出任何性能改进。可能是什么原因?实际的脚本使用 numpy、pandas 等库,并进行数据库连接以将输出写入稍后由 Web 服务器访问的进程。与 pypy 相比,numpy 或 pandas 在常规编译器中的编译速度是否更快?如果不是,还有什么可以解释这一点?另外,也欢迎任何加快速度的建议:)

PS Multiprocessing 已经被应用,它只比原始代码快大约 40 秒,这还不够。

编辑:在代码中添加 这是一个脚本,用于生成谁与谁接触了多长时间以及在哪里 - 医院的接触者追踪。基本上,它应该做的是,它读取一个 csv 文件,其中包含传感器在不同时间的所有位置,然后有一种算法可以生成所有联系人并将其写入数据库以供网络获取稍后服务器。

代码如下。它非常长,可能是我没有早点发布的原因:)

def resampleData(_beaconDevice, _timeInterval, _locationPtsX, _locationPtsY, 数据库):

database.child("contact").child("progress").set(20)
beaconData = pd.DataFrame({'timestamp': _timeInterval, 'Device': _beaconDevice, 'Beacon Longtitude': _locationPtsX, 'Beacon Latitude': _locationPtsY})
beaconData.set_index('timestamp', inplace=True)
beaconData.index = pd.to_datetime(beaconData.index)
beaconData = beaconData.groupby('Device').resample('S')['Beacon Longtitude', 'Beacon Latitude'].mean().ffill()
return beaconData
Run Code Online (Sandbox Code Playgroud)

def processTwo(connectedDev、temp、devicelist、increment、_patentlist、_beaconData、_start、_end、_devlist、_scale、数据库、用户、_distance):

for numPatients, patientName in enumerate(_patientlist):
    timestamp = _beaconData.loc[patientName, :].index.tolist()
    patientX = _beaconData.loc[patientName, 'Beacon Longtitude'].tolist()
    patientY = _beaconData.loc[patientName, 'Beacon Latitude'].tolist()
    progressUnit = (55/len(timestamp))
    for t, timeNum in enumerate(timestamp):
        if timeNum >= _start and timeNum <= _end:
            for device, devNum in enumerate(_devlist):
                if devNum != patientName:
                    if devNum in devicelist:
                        logger.log ("Finding Contacts...", timeNum)
                        if increment<55:
                            increment += progressUnit
                            try:
                                database.child("contact").child("progress").set(30+increment)
                            except: logger.info("exception")
                        isContact, contactLoc = inContact(patientName, patientX, patientY, devNum, t, _beaconData, _scale, _distance)
                        if isContact==True:
                            logger.log (patientName, "in contact with", devNum, "!")
                            temp.append(patientName)
                            temp.append(timeNum)
                            temp.append(int(devNum))
                            temp.append(patientX[t])
                            temp.append(patientY[t])
                            temp.append(contactLoc[0])
                            temp.append(contactLoc[1])
                            connectedDev.append(temp)
                            temp = []
Run Code Online (Sandbox Code Playgroud)

processsTwo 函数是代码中其他七个密集计算函数之一。for 循环处理 DataFrame。

aba*_*ert 5

\n

实际脚本使用 numpy、pandas 等库并执行数据库连接\xe2\x80\xa6

\n
\n\n

如果你的绝大多数时间都花在 numpy、pandas 和数据库调用上,而不是花在 Python 循环或计算上,那么 PyPy 几乎没有什么可以加速的。

\n\n

numpy 和 pandas 都是用 C 编写的扩展模块(带有一些 C++、Fortran 和汇编),大多数数据库库也是如此。扩展模块在安装时编译为本机代码。无论由什么解释器驱动,本机代码都会以完全相同的方式运行。特别是,它不会在 PyPy 中经历任何类型的 JIT。*所以,除非你在某个地方有一些重要的 Python 计算,否则 PyPy 无法使任何东西变得更快。

\n\n

与此同时,PyPy 实际上会让事情变得更慢。CPython 可以直接访问 numpy 等 C API 扩展,但 PyPy 必须伪装成 CPython 才能与扩展代码对话,这是通过一个名为 CPyExt 的包装器来实现的。PyPy 中 numpy 的常见问题解答称CPyExt 是“臭名昭著的慢”。这有点不公平/自嘲,尤其是在他们过去 5 年付出的努力之后;对于许多 numpy 程序,您甚至不会注意到其中的差异。但在某些情况下您仍然会这样做。您提到了多处理,许多情况都涉及跨进程共享数组。

\n\n

有时,使用numpypyfork(它以 PyPy 友好的方式重新实现 numpy 的核心)是值得做的。截至 2018 年,这是一个已弃用的解决方案(最后一点不完整的部分可能永远不会完成),但如果由于某种原因你确实需要一起使用 numpy 和 PyPy,并且你会遇到其中一个缓慢的解决方案地区,这仍然是一个选择。

\n\n
\n\n

* 如果您需要 JIT 数字代码,Jython 或 IronPython 可以与 JVM 或 .NET 运行时的数字库一起使用,它们确实通过 JIT 运行。然而,我不知道在大多数用例中它们中的任何一个实际上与 numpy 一样快。同时,您可能想numba在 CPython 中使用 numpy,它通常可以 JIT 您编写的包装器代码,以驱动 numpy 比 PyPy 更好地工作。

\n