并行:从同级文件夹导入 python 文件
Parallel: Import a python file from sibling folder
我有一个目录树
working_dir\
main.py
my_agent\
my_worker.py
my_utility\
my_utils.py
每个文件中的代码如下
""" main.py """
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from my_agent.my_worker import MyWorker
import ray
ray.init()
workers = [MyWorker.remote(i) for i in range(10)]
ids = [worker.get_id.remote() for worker in workers]
# print(*ids, sep='\n')
print(*ray.get(ids), sep='\n')
""" worker.py """
from my_utility import my_utils
import ray
@ray.remote
class MyWorker():
def __init__(self, id):
self.id = id
def get_id(self):
return my_utils.f(self.id)
""" my_utils.py """
def f(id):
return '{}: Everything is fine...'.format(id)
这是我收到的错误消息的一部分
Traceback (most recent call last):
File "/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/function_manager.py", line 616, in fetch_and_register_actor
unpickled_class = pickle.loads(pickled_class)
File "/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/cloudpickle/cloudpickle.py", line 894, in subimport
import(name)
ImportError: No module named 'my_utility'
Traceback (most recent call last):
File "main.py", line 12, in
print(*ray.get(ids), sep='\n')
File "/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/worker.py", line 2377, in get
raise value
ray.worker.RayTaskError: ray_worker (pid=30025, host=AiMacbook)
Exception: The actor with name MyWorker failed to be imported, and so cannot execute this method
如果我去掉所有与ray
相关的语句,上面的代码就可以正常工作了。因此,我大胆猜测原因是ray
运行s 新进程中的每个参与者,sys.path.append
仅在主进程中工作。所以我将以下代码添加到 worker.py
import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
但它仍然不起作用:出现相同的错误消息。现在我运行没主意了,怎么办?
您对问题的看法是正确的。
在您的示例中,您修改 main.py
中的 sys.path
以便能够导入 my_agent.my_worker
和 my_utility.my_utils
。
但是,此路径更改不会传播到工作进程,因此如果您要 运行 一个远程函数,例如
@ray.remote
def f():
# Print the PYTHONPATH on the worker process.
import sys
print(sys.path)
f.remote()
您会看到 worker 上的 sys.path
不包括您添加的父目录。
在 worker 上修改 sys.path
(例如,在 MyWorker
构造函数中)不起作用的原因是 MyWorker
class 定义被 pickle 并且运送给工人。然后 worker 解开它,解开 class 定义的过程需要导入 my_utils
,这失败了,因为 actor 构造函数还没有机会 运行。
这里有几个可能的解决方案。
运行 类似
的脚本
PYTHONPATH=$(dirname $(pwd)):$PYTHONPATH python main.py
(来自 working_dir/
)。这应该可以解决问题,因为在这种情况下,工作进程是从调度程序进程派生出来的(当您调用 ray.init()
时,它是从主 Python 解释器派生出来的,因此环境变量将由工作进程继承(这对于 sys.path
不会发生,大概是因为它不是环境变量)。
好像要加行
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.environ["PYTHONPATH"] = parent_dir + ":" + os.environ.get("PYTHONPATH", "")
in main.py
(在 ray.init()
调用之前)的工作原理与上述相同。
考虑添加 setup.py
并将您的项目安装为 Python 包,以便它自动位于相关路径上。
新的“运行时环境”功能在 post 时还不存在,应该有助于解决这个问题:https://docs.ray.io/en/latest/handling-dependencies.html#runtime-environments。 (参见 working_dir
和 py_modules
条目。)
我有一个目录树
working_dir\
main.py
my_agent\
my_worker.py
my_utility\
my_utils.py
每个文件中的代码如下
""" main.py """
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from my_agent.my_worker import MyWorker
import ray
ray.init()
workers = [MyWorker.remote(i) for i in range(10)]
ids = [worker.get_id.remote() for worker in workers]
# print(*ids, sep='\n')
print(*ray.get(ids), sep='\n')
""" worker.py """
from my_utility import my_utils
import ray
@ray.remote
class MyWorker():
def __init__(self, id):
self.id = id
def get_id(self):
return my_utils.f(self.id)
""" my_utils.py """
def f(id):
return '{}: Everything is fine...'.format(id)
这是我收到的错误消息的一部分
Traceback (most recent call last):
File "/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/function_manager.py", line 616, in fetch_and_register_actor unpickled_class = pickle.loads(pickled_class)
File "/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/cloudpickle/cloudpickle.py", line 894, in subimport import(name)
ImportError: No module named 'my_utility'
Traceback (most recent call last):
File "main.py", line 12, in print(*ray.get(ids), sep='\n')
File "/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/worker.py", line 2377, in get raise value ray.worker.RayTaskError: ray_worker (pid=30025, host=AiMacbook)
Exception: The actor with name MyWorker failed to be imported, and so cannot execute this method
如果我去掉所有与ray
相关的语句,上面的代码就可以正常工作了。因此,我大胆猜测原因是ray
运行s 新进程中的每个参与者,sys.path.append
仅在主进程中工作。所以我将以下代码添加到 worker.py
import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
但它仍然不起作用:出现相同的错误消息。现在我运行没主意了,怎么办?
您对问题的看法是正确的。
在您的示例中,您修改 main.py
中的 sys.path
以便能够导入 my_agent.my_worker
和 my_utility.my_utils
。
但是,此路径更改不会传播到工作进程,因此如果您要 运行 一个远程函数,例如
@ray.remote
def f():
# Print the PYTHONPATH on the worker process.
import sys
print(sys.path)
f.remote()
您会看到 worker 上的 sys.path
不包括您添加的父目录。
在 worker 上修改 sys.path
(例如,在 MyWorker
构造函数中)不起作用的原因是 MyWorker
class 定义被 pickle 并且运送给工人。然后 worker 解开它,解开 class 定义的过程需要导入 my_utils
,这失败了,因为 actor 构造函数还没有机会 运行。
这里有几个可能的解决方案。
运行 类似
的脚本PYTHONPATH=$(dirname $(pwd)):$PYTHONPATH python main.py
(来自
working_dir/
)。这应该可以解决问题,因为在这种情况下,工作进程是从调度程序进程派生出来的(当您调用ray.init()
时,它是从主 Python 解释器派生出来的,因此环境变量将由工作进程继承(这对于sys.path
不会发生,大概是因为它不是环境变量)。好像要加行
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) os.environ["PYTHONPATH"] = parent_dir + ":" + os.environ.get("PYTHONPATH", "")
in
main.py
(在ray.init()
调用之前)的工作原理与上述相同。考虑添加
setup.py
并将您的项目安装为 Python 包,以便它自动位于相关路径上。
新的“运行时环境”功能在 post 时还不存在,应该有助于解决这个问题:https://docs.ray.io/en/latest/handling-dependencies.html#runtime-environments。 (参见 working_dir
和 py_modules
条目。)