我用Ray创建了一个简单的远程函数,它占用的内存很少。但是,在运行了一小段时间后,内存稳步增加,我得到了RayOutOfMemoryError异常。
下面的代码是这个问题的一个非常简单的例子。“result_transformed”numpy数组被发送给工作者,每个工作者都可以处理这个数组。我的简化calc_similarity函数什么也不做,但是它仍然会耗尽内存。我已经为这个方法添加了更长的睡眠时间来模拟做更多的工作,但是它最终会耗尽内存。
我运行在一个8核英特尔9900 K与32 GB的内存和Ubuntu 19.10 Python是:英特尔Python发行版3.7.4 numpy为1.17.4(带英特尔mkl)
import numpy as np
from time import sleep
import ray
import psutil
@ray.remote
def calc_similarity(sims, offset):
# Fake some work for 100 ms.
sleep(0.10)
return True
if __name__ == "__main__":
# Initialize RAY to use all of the processors.
num_cpus = psutil.cpu_count(logical=False)
ray.init(num_cpus=num_cpus)
num_docs = 1000000
num_dimensions = 300
chunk_size = 128
sim_pct = 0.82
# Initialize the array
index = np.random.random((num_docs, num_dimensions)).astype(dtype=np.float32)
index_array = np.arange(num_docs).reshape(1, num_docs)
index_array_id = ray.put(index_array)
calc_results = []
for count, start_doc_no in enumerate(range(0, num_docs, chunk_size)):
size = min( chunk_size, num_docs - (start_doc_no) + 1 )
# Get the query vector out of the index.
query_vector = index[start_doc_no:start_doc_no+size]
# Calculate the matrix multiplication.
result_transformed = np.matmul(index, query_vector.T).T
# Serialize the result matrix out for each client.
result_id = ray.put(result_transformed)
# Simulate multi-threading extracting the results of a cosine similarity calculation
for offset in range(chunk_size):
calc_results.append(calc_similarity.remote(sims=result_id, offset=offset ))
# , index_array=index_array_id))
res = ray.get(calc_results)
calc_results.clear()
如有任何帮助/指导,我们将不胜感激。
2条答案
按热度按时间flseospp1#
谢谢你的回复。
问题是GC没有运行,因为在我用完32 GB系统上的内存之前,没有达到默认的阈值。
对ray.put(transformed_result)的调用可以占用相当大的内存(在本例中为128 x 1,000,000),或者使用float 32时占用大约0.5 GB的内存。
为了解决这个问题,我创建了一个方法,该方法执行以下操作,我可以在其中传入内存使用百分比阈值,并强制调用垃圾收集:
在我的核心处理循环中频繁调用这个函数可以解决内存不足的问题。
这种情况也可以通过修改垃圾收集中的阈值设置来解决。
这是非常依赖于任务的,并且取决于所使用的数据对象的大小,所以我觉得第一种方法是更好的选择。
谢谢你的详细回复!非常有帮助和启发。
kq0g1dla2#
目前,Ray部分支持引用计数。(完整的引用计数即将发布)简单地说,当传递给远程函数的object_id没有序列化时,它的引用计数方式与Python的引用计数方式相同,这意味着如果
result_transformed
被Python垃圾收集,那么plasma存储中的result_transformed
应该被解钉,当对象被LRU逐出时,它应该被逐出(为了清楚起见,具有一些引用计数的钉住对象不被逐出)。我还假设存在一些奇怪的引用计数,例如循环引用。我可以验证在运行此脚本时
result_transformed
被逐出。因此,我猜result_transformed
本身不是问题。可能存在许多问题。对于我的情况,我发现当我使用ipython作为输入时,它会创建对python对象的引用(IN).(例如,当你看到某个对象的值时,OUT[number]可以引用你的对象)。