Ray 比 Python 和 .multiprocessing 慢得多
Posted
技术标签:
【中文标题】Ray 比 Python 和 .multiprocessing 慢得多【英文标题】:Ray is much slower both than Python and .multiprocessing 【发布时间】:2020-03-01 07:18:37 【问题描述】:我上传了 13 万个 json 文件。
我用Python
做这个:
import os
import json
import pandas as pd
path = "/my_path/"
filename_ending = '.json'
json_list = []
json_files = [file for file in os.listdir(f"path") if file.endswith(filename_ending)]
import time
start = time.time()
for jf in json_files:
with open(f"path/jf", 'r') as f:
json_data = json.load(f)
json_list.append(json_data)
end = time.time()
这需要 60 秒。
我用multiprocessing
做这个:
import os
import json
import pandas as pd
from multiprocessing import Pool
import time
path = "/my_path/"
filename_ending = '.json'
json_files = [file for file in os.listdir(f"path") if file.endswith(filename_ending)]
def read_data(name):
with open(f"/my_path/name", 'r') as f:
json_data = json.load(f)
return json_data
if __name__ == '__main__':
start = time.time()
pool = Pool(processes=os.cpu_count())
x = pool.map(read_data, json_files)
end = time.time()
这需要 53 秒。
我用ray
做这个:
import os
import json
import pandas as pd
from multiprocessing import Pool
import time
import ray
path = "/my_path/"
filename_ending = '.json'
json_files = [file for file in os.listdir(f"path") if file.endswith(filename_ending)]
start = time.time()
ray.shutdown()
ray.init(num_cpus=os.cpu_count()-1)
@ray.remote
def read_data(name):
with open(f"/my_path/name", 'r') as f:
json_data = json.load(f)
return json_data
all_data = []
for jf in json_files:
all_data.append(read_data.remote(jf))
final = ray.get(all_data)
end = time.time()
这需要 146 秒。
我的问题是为什么ray
需要这么多时间?
是不是因为:
1) 对于相对少量的数据,ray 相对较慢?
2) 我的代码做错了什么?
3) ray
不是很有用吗?
【问题讨论】:
@RobertNishihara,有什么想法吗? Ray 是分布式计算的库,对吧? @AlexanderCécile,是的 :) 好吧,我目前正在做一些快速研究并试图写一个答案:) 您能分享一下用于测试的 JSON 文件吗? 【参考方案1】:我从未使用过 ray,但我很有信心,我的解释应该是正确的。
原始代码做了一个简单的 json 反序列化。该代码主要需要文件 IO 和一点点 CPU。 (json反序列化比较快,这也是json成为流行交换格式的原因之一)
Ray 必须将数据从一个进程推送到另一个进程(如果通过网络分布在多台机器上)。为了做到这一点,它自己执行一些序列化/反序列化(也许它使用 pickle 和一个健壮的 TCP 协议来推送参数和收集结果)。并且可能这个开销比实际任务所花费的工作量更大。
如果您对 json 数据进行更多计算(任何更占用 CPU 的数据),那么您将能够看到差异。
我的猜测是,您的示例问题太简单了,因此 ray 的开销超过了使用多个工作人员的好处。
换句话说。分配任务和收集结果所花费的时间/精力比实际执行计算结果所花费的时间/精力更多。
【讨论】:
你怎么知道 Ray 正在做任何与网络相关的事情? 我不知道,如果在单个主机上运行它是否真的是网络,如果使用集群它会。对于单主机设置,它可能只是本地 TCP 套接字、unix 域套接字、本地管道或共享内存。但在大多数情况下,序列化、反序列化、交换数据和同步都会产生相当大的开销。我调整了我的答案 我很确定 Ray 使用 Redis 服务器来处理进程间通信,甚至是本地通信,因此可能存在不可忽略的启动损失。结合这里的绝大多数工作是文件系统 I/O 的事实,我非常有信心 @gelonida 是正确的。【参考方案2】:我会说假设 1) 可能是最接近事实的。 Ray 看起来像一个强大的库,但你所做的只是读取一堆文件。您的代码只是为了进行基准测试,还是某个更大程序的一部分?如果是后者,那么让您的基准代码反映这一点可能会很有趣。
这没什么大不了的,但我调整了你的 3 个程序,所以它们至少应该更高效一些。
import os
import json
folder_path = "/my_path/"
filename_ending = '.json'
json_files = (os.path.join(folder_path, fp) for fp in os.listdir(f"folder_path") if fp.endswith(filename_ending))
def load_json_from_file(file_path):
with open(file_path, 'r') as file_1:
return json.load(file_1)
json_list = [load_json_from_file(curr_fp) for curr_fp in json_files]
import os
import json
import multiprocessing as mp
folder_path = "/my_path/"
filename_ending = '.json'
json_files = (os.path.join(folder_path, fp) for fp in os.listdir(f"folder_path") if fp.endswith(filename_ending))
def load_json_from_file(file_path):
with open(file_path, 'r') as file_1:
return json.load(file_1)
with mp.Pool() as pool:
json_list = pool.map(load_json_from_file, json_files)
import os
import json
import ray
folder_path = "/my_path/"
filename_ending = '.json'
@ray.remote
def load_json_from_file(file_path):
with open(file_path, 'r') as file_1:
return json.load(file_1)
json_files = (os.path.join(folder_path, fp) for fp in os.listdir(f"folder_path") if fp.endswith(filename_ending))
ray.init()
futures_list = [load_json_from_file.remote(curr_fp) for curr_fp in json_files]
json_list = ray.get(futures_list)
如果您有任何问题,请告诉我。如果您可以再次运行基准测试,我很想知道有什么区别(如果有的话)。
【讨论】:
您好,感谢您的回复(点赞)。我同意假设(1)在我的情况下可能更正确,尽管有待证明Ray
实际上在更大的数据下更好。顺便说一句,关于你的第二个代码块,你怎么不使用__main__
?我认为(基于其文档)要使用multiprocessing
,您必须使用__main__
?
@PoeteMaudit 哎呀,我忘记了这条评论,对不起!在 Windows 上使用 multiprocessing
时,__main__
似乎是绝对必要的。我使用的是 Mac,但无论如何写 __main__
部分对我来说可能是个好主意。请参阅here 了解为什么它在 Windows 上是必须的,here 了解有关该主题的更一般性讨论。
很酷,但我也让multiprocessing
运行:with mp.Pool(processes=os.cpu_count()-1) as pool: output = pool.map(my_function, input)
所以没有__main__
。
@PoeteMaudit 你没有使用 Windows?
啊是的好点。我在远程服务器上运行它,所以我不知道它是什么。我想是 Linux 吧?以上是关于Ray 比 Python 和 .multiprocessing 慢得多的主要内容,如果未能解决你的问题,请参考以下文章