我有一个正在运行的芹菜服务器,使用redis作为borker和结果存储(python3)。我想有一个任意函数,它没有被注册到服务器,由芹菜工人执行。我尝试使用包marshal(在Is there an easy way to pickle a python function (or otherwise serialize its code)?之后)序列化此函数,并将字节码传输给worker:
celery_server.py:
from celery import Celery
import types
import marshal
app = Celery('tasks', broker='redis://guest@localhost//', backend='redis://localhost')
@app.task
def run_fct( fct_code, args, kwargs ):
code = marshal.loads( fct.__code__ )
func = types.FunctionType(code, globals(), "some_func_name" )
return fct( *args, **kwargs )
client.py
from celery_server import run_fct
import marshal
def calc( x, y ):
return x*y
fct_code = marshal.dumps( calc.func_code )
run_fct.apply_async( (fct_code, 10, 2 ) )
我在客户端遇到以下错误:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe3 in position 0: invalid continuation byte
在bytes_to_str
的{{1}}函数中。
是否有另一种或更好的方法来执行我的功能?
感谢您的帮助。
答案 0 :(得分:0)
我找到了一个解决方案:通过包装我的函数并将包装函数作为参数提供给芹菜任务来解决UnicodeDecodeError
:
celery_server.py:
class MyFunction( object ):
def __init__(self, fct):
self.fct_code = marshal.dumps( fct.__code__ )
def run(self, *args, **kwargs):
run_fct.apply_async( args=(self,)+args, kwargs=kwargs, serializer='pickle' )
并在client.py中:
from celery_server import MyFunction
myFct = MyFunction( calc )
myFct.run( x=10, y=2 )
然后它就像一个魅力。
然而,使用包cloud解决了我的函数在工作者端的依赖性问题,例如,如果我在我的函数中使用了其他函数或包:
from celery import Celery
import cloud
import pickle
app = Celery('tasks', broker='redis://guest@localhost//', backend='redis://localhost')
class MyFunction( object ):
def __init__(self, fct):
self.serialized_code = cloud.serialization.cloudpickle.dumps(fct)
def run(self, *args, **kwargs):
run_fct.apply_async( args=(self,)+args, kwargs=kwargs, serializer='pickle' )
@app.task
def run_fct( myFct, *args, **kwargs ):
fct = pickle.loads( myFct.serialized_code )
return fct( *args, **kwargs )
client.py:
from tasks import MyFunction
import time
def calc( x, y ):
time.sleep(5)
return x*y
myFct = MyFunction( calc )
myFct.run( x=10, y=2 )
但是:当前cloud不支持python3。