用python处理一个1G左右的数据集,运行速度非常慢,怎样优化?
程序员文章站
2022-04-19 13:13:15
...
研究方向为推荐系统,最近用python在delicious数据集上实现一种简单的基于标签的推荐算法,然后计算recall和precision。在几M的小型数据集上运行时间还可以(十几秒左右),但是在较大(几百兆,1g)的数据集上运行非常慢,我等了4个小时还没有算出结果。请问一下在不对算法进行优化的基础上,采用什么样的方法可以提升程序的运行速度?
实验环境:Ubuntu 13.10, 4G, intel i3-2310M, python 2.75.
首先, 是算法的问题。复杂度不一样的算法, 在数据规模大的情况下, 运行速度差别会越来越大。你没有描述具体算法, 所以我们也不知道能怎样提升算法。不过根据我的经验, 机器学习算法慢很正常, 因为计算量非常大。很多步骤如果你参照现成一些方法的话, 基本就已经是已知的在算法复杂度和代码复杂度上做了非常好的平衡而且算法复杂度已经很不错的方法。 要想再提高的话要么就要投入大量时间做学术研究,或者大量时间编写复杂的代码。
解决方法是你要自己分析你的程序, 确定每一个部分的复杂度大概是多少,找出算法的瓶颈, 然后花精力优化瓶颈上的算法。
第二个问题是众所周知的 python 本身速度慢的问题,python作为完全建立在解释器上的支持OO支持FP且类型dynamic的语言, 能使用的机器指令优化非常有限,一般认为比native程序慢10-100倍是正常的。
解决方法:一个快速的 work-around 是使用 JIT 编译器例如 PyPy, 速度可以提高大概几倍到10倍左右。 另外,使用一个 profile 技术找到运行时间的瓶颈, 可以把瓶颈部分用 C 重写,即可几乎达到native速度。
最后, 在这个多核和云时代, 你应该考虑多核甚至多机器了。 Python 本身又 GIL, 一个进程内不支持计算意义上的多线程, 把你的程序各个部件好好划分一下, 分解成多进程。 然后用一台机器的多个CPU同时跑, 或者仍给多台机器跑。 题主,让我来给你一些实用建议吧!
试试一些奇怪的东西,比如PyPy.
单机情况下,总结起来,就是:首先减少输入数据,然后不要浪费机器资源,要让所有CPU核心跑满(多进程 & 减少/不等待IO),内存只要还够用的话,就可劲用!然后找程序最慢的地方,针对其做各种优化.
如果有多机,弄到hadoop里搞,数据再多也不怕不怕啦! 用delicious数据集即使是最naive的count(u,t)*(t,i)顺加inverse frequency都很慢吧。。。毕竟tag 和item都太多了。。。慢是正常的。。。 首先你应该确认一下你的算法复杂度,比如数据翻倍后运行时间增加多少? 正好看到这个 numfocus/python-benchmarks 路 GitHub profile + cython 一般来说最省力且最容易大幅度提升的反而是优化算法/使用profile优化实现。
其次是使用pypy/cython。
再其次使用numpy。
最后是改用其他语言。 python 数组遍历特别慢,可以结合 cython加速 i3-2310M?实验环境居然是在入门级笔记本上,你们实验室(公司)到底是有多困难? numpy是比较慢,矩阵运算量大可以试一下Matlab。另外可以profile一下你的程序,看看哪个环节运算时间比较长。
实验环境:Ubuntu 13.10, 4G, intel i3-2310M, python 2.75.
回复内容:
这里面有两个原因吧:首先, 是算法的问题。复杂度不一样的算法, 在数据规模大的情况下, 运行速度差别会越来越大。你没有描述具体算法, 所以我们也不知道能怎样提升算法。不过根据我的经验, 机器学习算法慢很正常, 因为计算量非常大。很多步骤如果你参照现成一些方法的话, 基本就已经是已知的在算法复杂度和代码复杂度上做了非常好的平衡而且算法复杂度已经很不错的方法。 要想再提高的话要么就要投入大量时间做学术研究,或者大量时间编写复杂的代码。
解决方法是你要自己分析你的程序, 确定每一个部分的复杂度大概是多少,找出算法的瓶颈, 然后花精力优化瓶颈上的算法。
第二个问题是众所周知的 python 本身速度慢的问题,python作为完全建立在解释器上的支持OO支持FP且类型dynamic的语言, 能使用的机器指令优化非常有限,一般认为比native程序慢10-100倍是正常的。
解决方法:一个快速的 work-around 是使用 JIT 编译器例如 PyPy, 速度可以提高大概几倍到10倍左右。 另外,使用一个 profile 技术找到运行时间的瓶颈, 可以把瓶颈部分用 C 重写,即可几乎达到native速度。
最后, 在这个多核和云时代, 你应该考虑多核甚至多机器了。 Python 本身又 GIL, 一个进程内不支持计算意义上的多线程, 把你的程序各个部件好好划分一下, 分解成多进程。 然后用一台机器的多个CPU同时跑, 或者仍给多台机器跑。 题主,让我来给你一些实用建议吧!
- 考虑拿C或C++重写.
- 考虑并行搞,找个hadoop集群,写成mapreduce程序跑 放在hadoop上跑,更多数据都不怕.
- 考虑升级机器,多搞点内存,然后东西尽量放在内存里搞.
- 考虑程序优化.
- 你得看看你程序慢在什么地方,可以按照以下步骤:
- 首先,确信你真的需要把全部数据过一遍,如果可以通过一些糙快猛方式过滤掉无用数据,这样最好了. (比如有些明显无用的东西可以直接通过grep过滤掉,grep这种程序写的一般比你写的python程序要快好多好多好多好多)
- top一下,看CPU跑满了吗?
- 单线程单进程实现?你能不能搞成多进程的?然后top看每个核都跑满了吗?
- 没跑满的话,那你你要努力充分利用你的CPU,要让CPU跑满!看看程序,没跑满是因为IO吗?是的话IO能搞成异步的么?或IO次数太多?能不能减少IO次数?甚至只搞一次IO,比如你那1G的东西,能不能一次全搞到内存里,然后所有东西在内存里处理(这样的话貌似写成C的更方便一点)
- 如果每个核心都跑满了,那就看看你的计算都花在什么地方,可以用hotshot等工具测一把. 可以粗略比较一下在 1/16 数据、1/8数据、1/4数据、1/2数据的情况下,hotshot的结果,看你的函数花的时间是怎么涨的.找出花时间最多的一个或几个东西(所谓瓶颈),有针对性的优化,可以事半功倍.
- 找到问题所在之后,寻求解决方案. 如果是python带的数据结构不不合适,能不能用numpy之类的东西解决,能不能用一些数据库解决(比如需要多个进程一起往一个大字典里写,可以考虑全往一个redis里写).能不能有的地方用cython包装一个C实现.
- 如果是算法不够好,能不能优化算法. (这就说来话长了)
单机情况下,总结起来,就是:首先减少输入数据,然后不要浪费机器资源,要让所有CPU核心跑满(多进程 & 减少/不等待IO),内存只要还够用的话,就可劲用!然后找程序最慢的地方,针对其做各种优化.
如果有多机,弄到hadoop里搞,数据再多也不怕不怕啦! 用delicious数据集即使是最naive的count(u,t)*(t,i)顺加inverse frequency都很慢吧。。。毕竟tag 和item都太多了。。。慢是正常的。。。 首先你应该确认一下你的算法复杂度,比如数据翻倍后运行时间增加多少? 正好看到这个 numfocus/python-benchmarks 路 GitHub profile + cython 一般来说最省力且最容易大幅度提升的反而是优化算法/使用profile优化实现。
其次是使用pypy/cython。
再其次使用numpy。
最后是改用其他语言。 python 数组遍历特别慢,可以结合 cython加速 i3-2310M?实验环境居然是在入门级笔记本上,你们实验室(公司)到底是有多困难? numpy是比较慢,矩阵运算量大可以试一下Matlab。另外可以profile一下你的程序,看看哪个环节运算时间比较长。