西芹工人在使用访问ZEO服务器的包时,都在等待任务的执行。但是,如果我直接在tasks.py
内访问服务器,就不会有任何问题。在
我有一个程序可以读写ZODB文件。因为我希望多个用户能够同时访问和修改这个数据库,所以我让它由一个ZEO server来管理,应该使它跨多个进程和线程安全。我在程序的一个模块中定义数据库:
from ZEO import ClientStorage
from ZODB.DB import DB
addr = 'localhost', 8090
storage = ClientStorage.ClientStorage(addr, wait=False)
db = DB(storage)
显然,我正在尝试更复杂的操作,但假设我只需要根对象或其子对象的键。我可以在这种情况下提出问题。在
我用上面的代码在一个模块中创建dummy_package
,以及一个用于执行数据库访问的基本模块:
如果不尝试使用dummy_package
进行任何数据库访问,则可以导入数据库并访问根目录而不会出现问题:
# tasks.py
from dummy_package import databases
@task()
def simple_task():
connection = databases.db.open()
keys = connection.root().keys()
connection.close(); databases.db.close()
return keys # Works perfectly
但是,尝试传递一个连接或root
的子级会使任务无限期挂起。在
@task()
def simple_task():
connection = databases.db.open()
root = connection.root()
ret = main.get_keys(root) # Hangs indefinitely
...
如果有什么不同的话,这些Celery任务由Django访问。在
那么,首先,这是怎么回事?以这种方式访问ZEO服务器是否会导致某种竞争状况?在
我可以让所有的数据库访问都由Celery负责,但这会导致代码变得难看。此外,它会破坏我的程序作为独立程序运行的能力。是不是不可能在芹菜工人的例行程序中与ZEO互动?在
不要将打开的连接或其根对象另存为全局。在
每个线程都需要一个连接;仅仅因为ZEO允许多个线程访问,所以听起来好像您使用的是非线程本地的(例如,在数据库.py). 在
将数据库保存为全局,但调用数据库打开()在每个任务期间。见http://zodb.readthedocs.org/en/latest/api.html#connection-pool
我不完全理解发生了什么,但我认为死锁与Celery默认使用^{} 进行并发有关。切换到对需要访问ZEO服务器的任务使用Eventlet解决了我的问题。在
我的流程
启动一个uses Eventlet,一个使用标准
multiproccesing
的工作线程。在celery
是默认队列(for historical reasons)的名称,因此让Eventlet工作线程处理此队列:Route tasks,它需要标准的
multiprocessing
到适当的队列。默认情况下,所有其他队列将被路由到celery
队列(Eventlet managed)。(如果使用Django,这将进入settings.py
):相关问题 更多 >
编程相关推荐