Python 为Ray actor函数实现缓存
我的目标是让下面的代码大约在0.3秒而不是0.5秒内执行。我尝试过使用Python 为Ray actor函数实现缓存,python,caching,ray,functools,toolz,Python,Caching,Ray,Functools,Toolz,我的目标是让下面的代码大约在0.3秒而不是0.5秒内执行。我尝试过使用functools.lru_cache、toolz.functoolz.memoize和kids.cache.cache上的装饰程序,但这些都不起作用(错误消息或未正确执行)。我能做些什么来让它工作 import ray @ray.remote class Foo: def foo(self, x): print("executing foo with {}".format(x)
functools.lru_cache
、toolz.functoolz.memoize
和kids.cache.cache
上的装饰程序,但这些都不起作用(错误消息或未正确执行)。我能做些什么来让它工作
import ray
@ray.remote
class Foo:
def foo(self, x):
print("executing foo with {}".format(x))
time.sleep(0.1)
ray.init()
f = Foo.remote()
s = time.time()
ray.get([f.foo.remote(x=i) for i in [1, 2, 1, 4, 1]])
print(time.time()-s)
ray.shutdown()
一般警告:如果函数产生副作用,缓存任意函数调用可能是危险的 在这种情况下,您可能希望程序输出
executing foo with 1
executing foo with 2
executing foo with 4
您提到的其他缓存工具往往无法与Ray配合使用,因为它们试图以某种全局状态存储缓存,而不是将该状态存储在可以以分布式方式访问的位置。因为您已经有了一个actor,所以您可以将全局状态存储在actor中
@ray.remote
class Foo:
def __init__(self):
self.foo_cache = {}
def foo(self, x):
def real_foo(x):
print("executing foo with {}".format(x))
time.sleep(0.1)
if x not in self.foo_cache:
self.foo_cache[x] = real_foo(x)
return self.foo_cache[x]
这是一种非常通用的缓存技术,唯一重要的区别是我们必须将状态存储在actor中
@ray.remote
class Foo:
def __init__(self):
self.foo_cache = {}
def foo(self, x):
def real_foo(x):
print("executing foo with {}".format(x))
time.sleep(0.1)
if x not in self.foo_cache:
self.foo_cache[x] = real_foo(x)
return self.foo_cache[x]
更广义的方法
通过定义通用函数缓存,我们还可以将此方法推广到任何光线函数:
@ray.remote
class FunctionCache:
def __init__(self, func):
self.func = ray.remote(func)
self.cache = {}
def call(self, *args, **kwargs):
if (args, kwargs) not in cache:
cache[(args, kwargs)] = self.func(*args, **kwargs)
return cache[(args, kwargs)]
然后,为了清理我们使用它的方式,我们可以定义一个装饰器:
class RemoteFunctionLookAlike:
def __init__(self, func):
self.func = func
def remote(self, *args, **kwargs):
return self.func(*args, **kwargs)
def ray_cache(func):
cache = FunctionCache.remote(func)
def call_with_cache(*args, **kwargs):
return cache.call.remote(*args, **kwargs)
return RayFunctionLookAlike(call_with_cache)
最后,要使用此缓存,请执行以下操作:
@ray_cache
def foo(x):
print("Function called!")
return abc
ray.get([foo.remote("constant") for _ in range(100)]) # Only prints "Function called!" once.
一般警告:如果函数产生副作用,缓存任意函数调用可能是危险的 在这种情况下,您可能希望程序输出
executing foo with 1
executing foo with 2
executing foo with 4
您提到的其他缓存工具往往无法与Ray配合使用,因为它们试图以某种全局状态存储缓存,而不是将该状态存储在可以以分布式方式访问的位置。因为您已经有了一个actor,所以您可以将全局状态存储在actor中
@ray.remote
class Foo:
def __init__(self):
self.foo_cache = {}
def foo(self, x):
def real_foo(x):
print("executing foo with {}".format(x))
time.sleep(0.1)
if x not in self.foo_cache:
self.foo_cache[x] = real_foo(x)
return self.foo_cache[x]
这是一种非常通用的缓存技术,唯一重要的区别是我们必须将状态存储在actor中
@ray.remote
class Foo:
def __init__(self):
self.foo_cache = {}
def foo(self, x):
def real_foo(x):
print("executing foo with {}".format(x))
time.sleep(0.1)
if x not in self.foo_cache:
self.foo_cache[x] = real_foo(x)
return self.foo_cache[x]
更广义的方法
通过定义通用函数缓存,我们还可以将此方法推广到任何光线函数:
@ray.remote
class FunctionCache:
def __init__(self, func):
self.func = ray.remote(func)
self.cache = {}
def call(self, *args, **kwargs):
if (args, kwargs) not in cache:
cache[(args, kwargs)] = self.func(*args, **kwargs)
return cache[(args, kwargs)]
然后,为了清理我们使用它的方式,我们可以定义一个装饰器:
class RemoteFunctionLookAlike:
def __init__(self, func):
self.func = func
def remote(self, *args, **kwargs):
return self.func(*args, **kwargs)
def ray_cache(func):
cache = FunctionCache.remote(func)
def call_with_cache(*args, **kwargs):
return cache.call.remote(*args, **kwargs)
return RayFunctionLookAlike(call_with_cache)
最后,要使用此缓存,请执行以下操作:
@ray_cache
def foo(x):
print("Function called!")
return abc
ray.get([foo.remote("constant") for _ in range(100)]) # Only prints "Function called!" once.
非常感谢你!我现在使用的是第一个简单的解决方案。我用的不是一本词典,而是一本非常好用的词典。非常感谢!我现在使用的是第一个简单的解决方案。我用的不是一本字典,而是一本非常好用的字典。