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

时间:2018-03-12 02:32:16

标签: python pandas numpy multiprocessing pypy

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

P.S多处理已经应用,它仅比原始代码快40秒,这是不够的。

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

代码如下。这是非常长的,可能是我之前没有发布的原因:)

def resampleData(_beaconDevice,_timeInterval,_locationPtsX,_locationPtsY,database):

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

def processTwo(connectedDev,temp,devicelist,increment,_patientlist,_beaconData,_start,_end,_devlist,_scale,database,user,_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 = []

processsTwo函数是代码中其他七个强大的计算函数之一。 for循环处理DataFrames。

1 个答案:

答案 0 :(得分:2)

  

实际脚本使用像numpy,pandas这样的库并进行数据库连接...

如果绝大部分时间花在numpy,pandas和数据库调用上,而不是Python循环或计算中,那么PyPy几乎没有任何时间可以加速。

numpy和pandas都是用C编写的扩展模块(带有一点C ++,Fortran和汇编),大多数数据库都是如此。扩展模块在安装时编译为本机代码。无论解释器驱动它,本机代码都将完全相同。特别是,它没有通过PyPy中的任何类型的JIT。 * 因此,除非你在某处有一些重要的Python计算,否则PyPy不能做得更快。

与此同时,PyPy实际上可以让事情变慢。 CPython可以直接访问像numpy这样的C API扩展,但是PyPy必须伪造CPython来与扩展代码通信,这可以通过一个名为CPyExt的包装器来实现。 PyPy中的FAQ numpy表示CPyExt是&#34;臭名昭着&#34;。这有点不公平/自我贬低,特别是在他们过去5年所做的所有工作之后;对于许多numpy程序,你甚至不会注意到差异。但是仍有一些情况你会这样做。并且您提到了多处理,并且许多情况涉及跨进程共享数组。

偶尔使用numpypy fork(以PyPy友好的方式重新实现numpy的核心)是值得的。截至2018年,这个被弃用的解决方案(最后一些不完整的位可能永远不会完成),但如果由于某种原因你真的需要一起使用numpy和PyPy,你就会遇到其中一个那些缓慢的领域,它仍然是一个选择。

*如果需要JIT数字代码,Jython或IronPython可以与JVM或.NET运行时的数字库一起使用,它们通过JIT运行。但是,我不知道其中任何一个对于大多数用例来说实际上和numpy一样快。同时,您可能希望在CPython中查看numba numpy,它通常可以JIT编写的包装代码,以便比PyPy更好地驱动您的numpy工作。