【问题标题】:Parallel: Import a python file from sibling folder并行:从同级文件夹导入 python 文件
【发布时间】:2019-06-17 16:17:54
【问题描述】:

我有一个目录树

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(最近一次调用最后一次):

文件“/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/function_manager.py”,第 616 行,在 fetch_and_register_actor unpickled_class= pickle.loads(pickled_class)

文件“/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/cloudpickle/cloudpickle.py”,第 894 行,在子导入中 进口(名称)

ImportError:没有名为“my_utility”的模块

Traceback(最近一次调用最后一次):

文件“main.py”,第 12 行,在 print(*ray.get(ids), sep='\n')

文件“/Users/aptx4869/anaconda3/envs/p35/lib/python3.5/site-packages/ray/worker.py”,第 2377 行,在获取 升值 ray.worker.RayTaskError: ray_worker (pid=30025, host=AiMacbook)

异常:名称为MyWorker的actor导入失败,无法执行该方法

如果我删除所有与ray相关的语句,上面的代码可以正常工作。因此,我大胆猜测原因是ray在一个新进程中运行每个actor,而sys.path.append仅在主进程中有效。所以我将以下代码添加到worker.py

import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

但它仍然不起作用:显示相同的错误消息。现在我的想法用完了,我该怎么办?

【问题讨论】:

  • 我认为os.path.dirname(os.path.dirname(__file__))os.path.join(os.path.dirname(__file__), '..') 更好
  • @spaniard 谢谢:-) 我猜你建议sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))。但这也不起作用......
  • 你试过删除if __name__ == '__main__' and __package__ is None:这行吗?并且总是将父目录添加到您的路径中?
  • @spaniard 是的,同样的故事还在继续
  • @Darkonaut 我按照你的建议做了,还是不行。我记得python3已经不再需要__init__.py了,不是吗?

标签: python parallel-processing distributed-system ray


【解决方案1】:

您对问题所在是正确的。

在您的示例中,您修改了main.py 中的sys.path,以便能够导入my_agent.my_workermy_utility.my_utils

但是,此路径更改不会传播到工作进程,因此如果您要运行类似的远程函数

@ray.remote
def f():
    # Print the PYTHONPATH on the worker process.
    import sys
    print(sys.path)

f.remote()

您会看到工作器上的sys.path 不包括您添加的父目录。

修改工作线程上的sys.path(例如,在MyWorker 构造函数中)不起作用的原因是MyWorker 类定义被腌制并运送给工作人员。然后worker unpickles它,unpickling类定义的过程需要导入my_utils,这失败了,因为actor构造函数还没有机会运行。

这里有几个可能的解决方案。

  1. 用类似的东西运行脚本

    PYTHONPATH=$(dirname $(pwd)):$PYTHONPATH python main.py
    

    (来自working_dir/)。这应该可以解决问题,因为在这种情况下,工作进程是从调度程序进程中派生出来的(当您调用 ray.init() 时,它是从主 Python 解释器派生出来的,因此工作人员将继承环境变量(这不会发生)对于sys.path 大概是因为它不是环境变量)。

  2. 好像加了一行

    parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    os.environ["PYTHONPATH"] = parent_dir + ":" + os.environ.get("PYTHONPATH", "")
    

    main.py 中(在ray.init() 调用之前)也出于与上述相同的原因。

  3. 考虑添加 setup.py 并将您的项目安装为 Python 包,以便它自动位于相关路径上。

【讨论】:

    猜你喜欢
    • 2018-07-19
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 2018-08-19
    相关资源
    最近更新 更多