您可以使用 ctypes 通过其内存 id 将对象传递给 celery 任务吗?

Posted

技术标签:

【中文标题】您可以使用 ctypes 通过其内存 id 将对象传递给 celery 任务吗?【英文标题】:Can you pass an object to a celery task by its memory id using ctypes? 【发布时间】:2019-10-30 21:25:06 【问题描述】:

我想将我自己的类的对象传递给 celery 任务。我没有使用 Django,这是我自己的自定义类,不可序列化。

经过研究,我想到了将对象内存id作为参数传递,然后根据this answer从id中获取对象:

tasks.py

import ctypes

@app.task
def my_task(obj_memory_id):
    my_obj = ctypes.cast(obj_memory_id, ctypes.py_object).value
    my_obj.my_method()

ma​​in.py

def main():
    obj = MyClass()
    obj_memory_id = id(obj)
    my_task.delay(obj_memory_id)

现在,当我在 celery 之外执行它时,它可以工作。但是当我用芹菜做时,我得到:

billiard.exceptions.WorkerLostError: Worker exited prematurely: signal 11 (SIGSEGV).

为什么会这样?我该如何实现我的目标?

更多信息:我没有在 Celery 任务中实例化该类,因为该类实例化非常慢(1-2 秒)。就我的目的而言,即使是 1 秒的延迟也很多。我想提前准备好它的实例,当我需要调用它的方法时,立即执行。

【问题讨论】:

永远,永远在生产代码中这样做:ctypes.cast(obj_memory_id, ctypes.py_object).value @juanpa.arrivillaga 为什么? 因为它依赖于实现细节(id 是 PyObject 标头的内存地址)和不安全的强制转换。无论如何,您的 celery 进程将无法从这样的单独进程中理解内存地址,请参阅:***.com/questions/4352668/… @juanpa.arrivillaga 谢谢。那么你知道有什么方法可以将不可序列化的对象传递给 celery 任务吗? 不,它必须是可序列化的。 【参考方案1】:

celery worker 在不同的进程中运行,可能在不同的机器上。不太可能与产生任务的进程共享内存。您正在向任务传递一个随机指针,该任务取消引用它并且您得到垃圾。

如果您想以有用的方式使用 Celery,您需要以某种方式使您的对象可序列化。通过使其可腌制或更好的方式。

【讨论】:

如果在同一台机器上运行(包括broker)就不可能吗? @NikolayShindarov 你可以这样做,但你为什么要运行 Celery? 假设我有类似观察者模式的东西。但是当我从观察者调用观察者的更新方法时,我想在后台异步调用它并继续运行观察者而不等待观察者的执行。那么有什么方法可以实现我想要的吗? @NikolayShindarov 只是使用线程,对吗?如果你不能序列化你的任务参数,Celery 就没用了。 我可能会查看线程,谢谢。但是我还是不明白,如果任务参数不可序列化,为什么 Celery 没用?

以上是关于您可以使用 ctypes 通过其内存 id 将对象传递给 celery 任务吗?的主要内容,如果未能解决你的问题,请参考以下文章

将 C++ 中的“extern C”与 ctypes 的向量一起使用

如何通过 ctypes 将(非空)列表从 Python 传递到 C++?

Python ctypes 中的指针和数组

将 multiprocessing.Value 对象传递给 ctype 函数?

静态方法内存分配

使用 numpy/ctypes 公开 C 分配的内存缓冲区的更安全方法?