多个进程共享一个 Joblib 缓存
Posted
技术标签:
【中文标题】多个进程共享一个 Joblib 缓存【英文标题】:Multiple processes sharing a single Joblib cache 【发布时间】:2014-09-21 21:45:26 【问题描述】:我正在使用 Joblib 在我的 python 脚本中缓存计算量大的函数的结果。函数的输入参数和返回值是 numpy 数组。缓存适用于我的 python 脚本的单次运行。现在我想并行生成我的 python 脚本的多个运行,以便在实验中扫描一些参数。 (函数的定义在所有运行中保持相同)。
有没有办法在并行运行的多个 python 脚本之间共享 joblib 缓存? 这将节省大量在不同运行中重复但在单次运行中不重复的函数评估。我在Joblib's documentation 中找不到这是否可行
【问题讨论】:
如果您已经在脚本的单次运行中进行了并行化,我认为尝试在多次运行中进行并行化也不会有什么好处。我想您可以通过重新使用以前运行的缓存来做得更好。我从未尝试过,但我猜你可以通过在连续运行中使用相同的joblib.Memory
对象来做到这一点。
@ali_m:单次运行是并行的,但我也需要并行运行多次,因为每次运行需要几天时间,而且我有很多内核(我在簇)。如果 joblib 的缓存是一个文件,那么看起来应该可以让多个进程共享它......我不知道如何。
单次运行时,您的核心利用率如何?如果您已经在一次运行中使用了所有内核,那么通过跨运行并行化您将无法做得更好 - 额外的工作线程只会竞争同一组内核,您可能会很好看到由于额外的线程开销和缓存冲突导致的性能下降。跨运行而不是在单个运行中并行化可能更有意义 - 这样您将花费成比例地减少生成和终止线程而不是进行计算的时间。
如果您 mem.cache
重复自身的功能,那么这应该可以开箱即用。至少在一台具有多处理功能的机器上。在不共享磁盘空间的多台机器的集群上,这是完全不同的事情。如果他们确实共享磁盘空间并且您将缓存放在那里,我不明白为什么它不应该工作。
@eickenberg...谢谢!! :) 我想我正在使用 cachedir = mkdtemp() ,这就是它以前不起作用的原因。只要两个进程使用相同的目录来保存缓存,它就可以工作。
【参考方案1】:
指定一个通用的、固定的cachedir
并装饰您要使用的缓存函数
from joblib import Memory
mem = Memory(cachedir=cachedir)
@mem.cache
def f(arguments):
"""do things"""
pass
或者干脆
def g(arguments):
pass
cached_g = mem.cache(g)
那么,即使你跨进程、跨机器工作,如果你的程序的所有实例都可以访问cachedir
,那么公共函数调用可以透明地缓存在那里。
【讨论】:
确实,我们(joblib 开发团队)非常谨慎地设计基于磁盘的存储,使其对并行访问(并且主要是并行写入)具有鲁棒性。作为旁注,我倾向于在上述答案中使用第二种语法而不是第一种语法。 @GaelVaroquaux,您能否详细说明为什么您更喜欢后者?我的 Tornado 网络应用程序中到处都是@mem.cache
,我想知道是否有理由将它们重构为推荐的替代方案。谢谢!
@GaelVaroquaux 另外,我想知道是否值得为异步访问装饰一个函数,例如使用 `@gen.coroutine` 如果 fetch 任务比平时花费更长的时间并且该函数是从 HTTP 端点调用的或延迟敏感客户。谢谢!
我认为@
-notation 只是第二个的简写版本。所以第二个明确了装饰的含义,它使您有可能不丢失原始的非装饰功能。在某些情况下,尤其是在交互式会话中,由于名称更改,只有第二个选项有效。
@GaelVaroquaux 很长一段时间后回复......当你说“主要是并行写入”时,“主要”是什么意思。有什么重要的陷阱吗?他们在某处有记录吗?谢谢。以上是关于多个进程共享一个 Joblib 缓存的主要内容,如果未能解决你的问题,请参考以下文章