2

我正在运行测试:

client = Client('127.0.0.1:8786')

def x(i):
    return {}

while True:
    start = time.time()
    a = client.submit(randint(0,1000000))
    res = a.result()
    del a
    end = time.time()
    print("Ran on %s with res %s" % (end-start, res))

client.shutdown()
del client

我使用它(带有更多代码)来估计我的查询性能。但是对于这个例子,我已经删除了所有我能想到的东西。

上面的代码每秒泄漏大约 0.1 MB,我估计每 1000 次调用大约 0.3 MB。

我在我的代码中做错了吗?

4

2 回答 2

1

我的 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 (in distributed/utils.py)中调用的

这是 LRU 缓存,最多可容纳 100 000 个项目。

第二次尝试
根据代码,它显示为 Dask 应该攀升到大约 10k_lru_list_elem

在再次运行我的脚本并观察内存之后,它会快速攀升,直到我接近 100k _lru_list_elem,之后它几乎完全停止了攀升。

情况似乎是这样,因为它在 100k 之后几乎是平线

Dask 的内存使用情况

所以没有泄漏,但是在 Dask 源代码和 Python 内存分析器上弄脏手很有趣

于 2017-10-04T14:54:44.347 回答
0

出于诊断、日志记录和性能方面的原因,Dask 调度程序在固定大小的双端队列中记录其与工作人员和客户端的许多交互。这些记录确实会累积,但只是在有限的范围内。

我们还努力确保我们不会保留任何太大的东西。

看到内存使用率上升到一个不错的整数,就像你所看到的那样,然后保持稳定似乎与此一致。

于 2017-10-04T15:09:42.203 回答