Python 内存占用也太大了。

2018-09-25 10:12:15 +08:00
 skinny

我现有 5 个 collections.Counter 的 pickle 文件,单个文件在 84MB-240MB 之间,总共 664MB,总记录在 3 千多万,实际数据大小也就 400MB 左右。之所以分为 5 个文件是因为之前有几个 GB 的数据,我电脑内存小( 6GB ),又是机械硬盘,根本没办法一下子读取和处理,我分割成小块处理,最后变成了这 5 个文件,然后我想合并这些文件进行最后处理。

最终合并前,我预估过用 C 实现类似的字典( D[char[10],uint])合并,内存用的不会很多,即便是最粗糙的字典实现也只需要 680M 左右内存,我看 pickle 文件加起来才 664MB,就算翻 4 翻的内存占用机器也撑得住,可是一运行内存就被耗光,然后机器死机了,只能强制关机,根据死机前的 Python 占用情况,最终可能需要内存要 6GB-8GB 才能加载处理总共 664M 的这 5 个 pickle 文件。(只有 load 和 plus 操作)

可能有人会问我为什么不用 Redis 或者数据库查询,因为我没安装,我也就这一次需要以这种方式处理这种文件。前面用 Python 处理单个小文件时还好,虽然速度不敢恭维,不过还能接受,胜在写起来简单方便。

目前对 Python 感受就是慢、吃内存,但是写起来简单(当然也有非常复杂的,比如 asynio ),真的是胶水一样的语言。

22650 次点击
所在节点    Python
98 条回复
xrui
2018-09-26 11:53:32 +08:00
@lihongjie0209
不知这样杠精你可满意?任务管理器表面每 5 秒 python 内存使用增加 1M

import requests
import time
from lxml import etree

urls = ["https://movie.douban.com/subject/25820460/?from=subject-page"]
visited=[]
for i in range(100):
try:
url=urls[0]
visited.append(url)
urls.pop(0)
data = requests.get(url).text
s=etree.HTML(data)
title=s.xpath('//*[@id="content"]/h1/span[1]/text()')[0]
nextu=s.xpath('//*[@id="recommendations"]/div/dl[5]/dd/a/@href')[0]
urls.append(nextu)
time.sleep(5)
except:
print("sth")
else:
print(title)
lihongjie0209
2018-09-26 12:49:20 +08:00
@xrui 我都不想说你, 自己看看代码写的什么鬼样

只爬取前 20 条:


types | # objects | total size
==================================== | =========== | ============
<class 'str | 34273 | 4.89 MB
<class 'dict | 4859 | 2.61 MB
<class 'type | 1402 | 1.42 MB
<class 'code | 9838 | 1.36 MB
<class 'set | 1073 | 508.22 KB
<class 'tuple | 4423 | 289.40 KB
<class 'list | 2457 | 287.18 KB
<class 'weakref | 2903 | 226.80 KB
<class 'wrapper_descriptor | 2383 | 186.17 KB
<class 'builtin_function_or_method | 2607 | 183.30 KB
<class 'abc.ABCMeta | 146 | 145.60 KB
<class 'getset_descriptor | 1873 | 131.70 KB
<class 'int | 4203 | 125.74 KB
<class 'method_descriptor | 1358 | 95.48 KB
function (__init__) | 688 | 91.38 KB
美国队长 3 Captain America: Civil War
蚁人 Ant-Man
钢铁侠 Iron Man
X 战警 X-Men
蜘蛛侠 Spider-Man
我,机器人 I, Robot
终结者 The Terminator
变形金刚 Transformers
我,机器人 I, Robot
终结者 The Terminator
变形金刚 Transformers
我,机器人 I, Robot
终结者 The Terminator
变形金刚 Transformers
我,机器人 I, Robot
终结者 The Terminator
变形金刚 Transformers
我,机器人 I, Robot
终结者 The Terminator
变形金刚 Transformers
types | # objects | total size
==================================== | =========== | ============
<class 'str | 34427 | 5.27 MB
<class 'dict | 4878 | 2.62 MB
<class 'type | 1410 | 1.44 MB
<class 'code | 9866 | 1.36 MB
<class 'set | 1073 | 508.72 KB
<class 'tuple | 4461 | 292.20 KB
<class 'list | 2488 | 291.38 KB
<class 'weakref | 2917 | 227.89 KB
<class 'wrapper_descriptor | 2383 | 186.17 KB
<class 'builtin_function_or_method | 2608 | 183.38 KB
<class 'abc.ABCMeta | 146 | 147.05 KB
<class 'getset_descriptor | 1878 | 132.05 KB
<class 'int | 4216 | 126.14 KB
<class 'method_descriptor | 1358 | 95.48 KB
function (__init__) | 695 | 92.30 KB


爬取 20 条之后 str 的内存占用增加了 0.38M, 与你的描述: 每个网址大概消耗 1M 多内存 存在较大的差异, 需要你提供你的内存占用测试以及结果


计算内存占用的方法:

from pympler import summary
from pympler import muppy
def print_mem():
summarize = summary.summarize(muppy.get_objects())
summary.print_(summarize)

参考文档:
https://pythonhosted.org/Pympler/muppy.html#muppy
lihongjie0209
2018-09-26 12:50:25 +08:00
@lihongjie0209 最开始的那句话发错了, 和本问题无关
mathgl
2018-09-26 13:49:53 +08:00
@lihongjie0209 他是在一本正经地扯蛋而已。
leemove
2018-09-26 13:54:27 +08:00
小伙子敢吐槽 python 勇气可嘉.v 站只允许吐槽 js,php 辣鸡,python 是上等语言,上等语言的事能叫占用内存多吗?
lihongjie0209
2018-09-26 14:10:03 +08:00
@xrui

print_mem()
l = []
for i in range(20):
l.append("https://movie.douban.com/subject/25820460/?from=subject-page")
# time.sleep(.5)

print_mem()

自己测试一下完全只 append string 的内存占用, 几乎没有



你的内存上涨只可能是 python 的 gc 没有把 垃圾回收而已, 如果你需要准确控制垃圾回收, 那么自动 gc 的语言不适合你
lihongjie0209
2018-09-26 14:10:46 +08:00
@leemove 吐槽要有理有据, 瞎 BB 谁也会
newghost
2018-09-26 16:09:38 +08:00
Java 情何以堪
d18
2018-09-26 17:07:20 +08:00
成功钓出一群杠精?
firebroo
2018-09-26 18:54:37 +08:00
python 肯定大。。正常。https://github.com/firebroo/UnixTools/blob/master/uniq/hashtable.h 你说的粗糙的 c 的 hashmap,不能说是粗糙,这东西越精细内存占用越大,只能说精简。
clino
2018-09-26 21:42:44 +08:00
楼上你们贴代码怎么都不用 gist?特别是对于 python 这种缩进严格的语言...
jswangjieda
2018-09-27 09:43:16 +08:00
python 完全面向对象,包括 int,float 这种数字都是对象,内存占用更多好像也没啥奇怪的,原生 python 在性能上本来就不好,一般数据处理的话还是用 numpy 这种用 cython 写的库。拿 python 直接去和 java,c 之类的语言对比内存占用和运行速度本来就不对吧。
skinny
2018-09-27 09:51:34 +08:00
@jswangjieda 我一开始没有直接去和 java,c 之类的语言对比,我开始说的是 Python 内存占用远远超过预估,所以吐槽了下 Python 内存占用太多(就这次的经验来看,大量小数据(超千万)不适合用标准库和内置容器对象)。可是炸出来一群杠精,所以才有后面别的语言的处理代码和结果。

@newghost Java 分配 3.5GB 内存可以搞定的,就是 CPU 使用率有点高。
skinny
2018-09-27 09:55:02 +08:00
@clino 太麻烦,且主要是代码太简单。还有吐槽下主贴有支持 markdown,回复却不支持,还要删除回复全部行首空格。
clino
2018-09-27 10:01:35 +08:00
@skinny 你是没用过 gist 吗? 怎么会麻烦? 只要编辑好这里提供地址就行了
jswangjieda
2018-09-27 10:10:51 +08:00
@skinny python 完全面向对象和动态类型的特性乍一看很美,但是对需要高性能的需求来说无异于是毒瘤,好在有 cython/numba 等库的支撑,不然 python 在科学计算上也不会这么好用
skinny
2018-09-27 10:25:55 +08:00
@jswangjieda 估计等下要杠你了
jswangjieda
2018-09-27 10:42:05 +08:00
@skinny hahaha,没事没事,我只是说了我知道的事情,我本来就只拿 python 捣腾机器学习,其他方面又不懂,要是有人拿他们懂的东西来杠我,我也懒得回应

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/492253

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX