我的 python 调试技能有点生疏(我的意思是我最后一次在 Orbited(websockets 的前身)上使用 objgraph 是在 2009 年https://pypi.python.org/pypi/orbited),但据我所知,检查之前和之前的引用数量之后:
在使用objgraph.show_most_common_types()之前和之后统计调度器中的对象
| What | Before | After | Diff |
|-------------+------------------+--------|---------+
| function | 33318 | 33399 | 81 |
| dict | 17988 | 18277 | 289 |
| tuple | 16439 | 28062 | 11623 |
| list | 10926 | 11257 | 331 |
| OrderedDict | N/A | 7168 | 7168|
无论如何,这不是一个巨大的RAM数量,但深入挖掘我发现 t scheduler._transition_counter 是 11453 并且 scheduler.transition_log 充满了:
('x-25ca747a80f8057c081bf1bca6ddd481', 'released', 'waiting',
OrderedDict([('x-25ca747a80f8057c081bf1bca6ddd481', 'processing')]), 4121),
('x-25ca747a80f8057c081bf1bca6ddd481', 'waiting', 'processing', {}, 4122),
('x-25cb592650bd793a4123f2df39a54e29', 'memory', 'released', OrderedDict(), 4123),
('x-25cb592650bd793a4123f2df39a54e29', 'released', 'forgotten', {}, 4124),
('x-25ca747a80f8057c081bf1bca6ddd481', 'processing', 'memory', OrderedDict(), 4125),
('x-b6621de1a823857d2f206fbe8afbeb46', 'released', 'waiting', OrderedDict([('x-b6621de1a823857d2f206fbe8afbeb46', 'processing')]), 4126)
我的第一个错误
这当然让我意识到我的第一个错误是没有配置转换日志长度。
将配置transition-log-length设置为10后:
| What | Before | After | Diff |
| ---------------+----------+--------+---------|
| function | 33323 | 33336 | 13 |
| dict | 17987 | 18120 | 133 |
| tuple | 16530 | 16342 | -188 |
| list | 10928 | 11136 | 208 |
| _lru_list_elem | N/A | 5609 | 5609 |
快速谷歌发现_lru_list_elem 是由@functools.lru_cache 生成的,而key_split 又调用了distributed/utils.py(在distributed/utils.py 中)
这是 LRU 缓存,最多 100 000 个项目。
第二次尝试
根据代码,它显示为 Dask 应该上升到大约 10k _lru_list_elem
在再次运行我的脚本并观察内存后,它会快速攀升,直到我接近 100k _lru_list_elem,之后它几乎完全停止了攀升。
似乎是这样,因为它在 100k 之后几乎是平线
所以没有泄漏,但接触 Dask 源代码和 Python 内存分析器很有趣