查看source, rq 只是检查您的函数的__module__
属性,可以进行微不足道的更改。问题是,为什么rq 会限制您将工作从 入队__main__
?一定有一些原因,而且有:函数的模块必须是worker可导入的。__main__
不是,因为您的主模块未__main__.py
在磁盘上命名。请参阅本页底部的“工作注意事项” 。
此外,您的脚本中包含顶级(非定义)代码,每次由工作人员导入时都会重新调用,您可能不想这样做,因为它将创建新队列并填充它们每个工人开始时的工作,无限。如果你想在你的主模块中加入一个函数,你可以并且应该使用一个if __name__ == "__main__"
守卫来防止这种递归行为。
如果您想将函数及其入队保留在单个模块中,我的建议是,除了函数和/或类定义之外,不要将任何顶级代码放入其中。任何可能是顶级代码的东西,都写成一个函数(名为 eg main()
)。然后编写一个“虚拟”主模块,导入您的真实模块并开始处理。
例子:
一些模块.py
from redis import Redis
from rq import Queue
def somefunc():
do_something()
def main():
q = Queue(connection=Redis('redis://redis'))
q.enqueue(somefunc)
# if the user tried to execute this module, import the right one for them.
# somemodule is then imported twice, once as __main__ and once as somemodule,
# which will use a little extra memory and time but is mostly harmless
if __name__ == "__main__":
import mainmodule
主模块.py
import somemodule
somemodule.main()
您也可以__module__
将函数的属性更改为磁盘上模块的实际名称,以便可以导入它。您甚至可以编写一个装饰器来自动执行此操作:
from sys import modules
from from os.path import basename, splitext
def enqueueable(func):
if func.__module__ == "__main__":
func.__module__, _ = splitext(basename(modules["__main__"].__file__))
return func
@enqueueable
def somefunc():
do_something()
if __name__ == "__main__":
from redis import Redis
from rq import Queue
q = Queue(connection=Redis('redis://redis'))
q.enqueue(somefunc)
为简单起见,装饰器假定您的模块是一个可以在其文件名下导入的单个文件,并且.py
去掉了扩展名。您可能正在为您的主模块使用一个包,其中事情会变得更加复杂......所以不要这样做。