如何优化 Python 计算超大字典的问题

2021-02-04 15:20:27 +08:00
 WilliamHL

目前遇到一个这样的问题: 从数据库中读取数据,存到字典的内存中(减少读取带来的性能消耗), 字典的键是 int 类型,字典的值是 longtext,一次读取大概 200 条左右的数据,后续可能会过千。 这个字典超级大,涉及到代码运算中还有其他计算、字典的 copy 、声明新的 list 等等操作,会存在多个这样的数据,导致虚拟内存峰值飙升到接近 50GB,mackbook 都是 oom 。

只想到是不是可以采用 redis 来代替字典操作,减少内存消耗,不知道还有没有其他方式,感谢各位 v 友~

3220 次点击
所在节点    Python
30 条回复
WilliamHL
2021-02-05 11:27:07 +08:00
@DoctorCat 大概就是 19 楼和 20 提到的问题,value 计算了很多中间层的 list 和 str 造成的,但是目前这些都是需要进行的中间层计算,暂时没有想到好的办法
WilliamHL
2021-02-05 11:31:07 +08:00
@Wincer 是这样的但是不知道有没有什么好的办法,最后坏的办法就是进行分次读取,但是感觉多 db 读取,会造成程序执行时间过长
DoctorCat
2021-02-05 11:44:53 +08:00
@WilliamHL 善用 Del
kele1997
2021-02-05 14:26:06 +08:00
你使用的是多进程,而不是多线程。多进程传参,参数会拷贝到新的子进程中。

你可以试试下面的代码,你会发现,一个进程的时候,内存占用在 400 MB 左右
多个进程的时候,每个进程占用内存都在 400MB 左右

而且使用多进程模块时,还有一个等待的主进程模块,所以你的参数拷贝了好多次之后,内存就爆炸了。。

```python3
import time
from multiprocessing import Process

ll = [i for i in range(10000000)]



def test(ll):
····while True:
····¦···time.sleep(0.1)

p1 = Process(target=test, args=(ll,))
p1.start()

# 开第二个 注释掉 p1.join
p1.join()
# 再开新的进程
'''
p2 = Process(target=test, args=(ll,))
p2.start()

p1.join()
'''
```
kele1997
2021-02-05 14:35:00 +08:00
另外你可以尝试使用一下 pypy 解释器,在上面的代码中,使用 cpython 解释器每个进程占用内存 400MB 左右,而使用 pypy 解释器只需要打给虚拟内存 200 MB,实际物理占用 140MB !!
WilliamHL
2021-02-05 14:41:23 +08:00
@DoctorCat 尝试了一下 del 确实比 pop 占用多一些内存。感觉峰值内存还是在切片和推导上
WilliamHL
2021-02-05 14:43:20 +08:00
@kele1997 感谢,我去尝试一下。多进程是后来改写的,还没有验证,数据上都是之前单进程执行出现的
kele1997
2021-02-05 14:45:14 +08:00
看到上面还有老哥说,许多中间变量也占用内存,可以使用 DEL 删除。其实 python3 的垃圾回收是引用奇数,我们可以把前面的计算都包装到函数中,函数的作用域结束之后,函数内部的内存都会回收掉

例如,还是下面的代码,使用函数,创建列表之后,主进程只需要 10 几兆的内存,而只有工作进程 p1 才会占用 400MB 内存

```python
def createlist():
ll = [i for i in range(10000000)]
# 这里可以添加一些中间结果,比如 tmp 之类的中间结果,这些都会回收掉
tmp = [j for j in range(1111,1111111)]
return ll

print(gc.isenabled())


def test(ll):
while True:
time.sleep(0.1)



p1 = Process(target=test, args=(createlist(),))
p1.start()


p1.join()
```
Wincer
2021-02-05 14:45:51 +08:00
@WilliamHL 使用 memoryview 试试吧,先把 str 转成 memoryview,进行切片操作和修改操作,在操作完成的时候再转化回来。
ghostviper
2021-02-08 10:04:46 +08:00
best practise 请使用 pandas 来操作

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

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

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

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

© 2021 V2EX