[英]Tornado background task using cx_Oracle
我需要服务器在某些时候刷新一些数据。 这是通过使用Cx_Oracle从Oracle数据库中获取行来完成的 。
多亏了Tornado的PeriodicCallback ,该程序每30秒检查一次是否应该加载新数据:
server.start()
from tornado.ioloop import PeriodicCallback
pcallback = PeriodicCallback(db_obj.reload_data_async, 10 * 1e3)
pcallback.start()
server.io_loop.start()
其中db_obj
是一个类的实例,该类负责与DB相关的功能(连接,提取,...)。
基本上,这就是reload_data_async
函数的样子:
executor = concurrent.futures.ThreadPoolExecutor(4)
# methods of the db_obj class ...
@gen.coroutine
def reload_data_async(self):
# ... first, some code to check if the data should be reloaded ...
# ...
if data_should_be_reloaded:
new_data = yield executor.submit(self.fetch_data)
def fetch_data(self):
""" fetch new data in the DB """
cursor = cx.Cursor(self.db_connection)
cursor.execute("some SQL select request that takes time (select * from ...)")
rows = cursor.fetchall()
# some more processing thereafter
# ...
基本上,这可行。 但是,当我尝试在将数据加载到fetch_data
(通过单击以在GUI中显示)读取数据时,该程序由于竞态条件而崩溃(我猜是吗?):它正在同时获取数据时正在访问数据。
我刚刚发现tornado.concurrent.futures不是线程安全的:
tornado.concurrent.Future与current.futures.Future相似,但不是线程安全的(因此与单线程事件循环一起使用时更快)。
总而言之,我认为我应该创建一个新线程来处理CX_Oracle操作。 我可以使用Tornado并继续使用PerodicCallback
函数吗? 如何将异步操作转换为线程安全的? 这是怎么做的?
PS:我正在使用Python 2.7
谢谢
解决了!
@Sraw是正确的:它不会导致崩溃。
说明 : fetch_data()
使用的是cx Oracle Connection对象( self.db_connection
),默认情况下该对象不是线程安全的。 如Cx Oracle文档中所述,将threaded
参数设置为True
可以用互斥体包装共享连接。
threaded参数应为布尔表达式,该表达式指示Oracle是否应使用互斥体包装对连接的访问。 在单线程应用程序中这样做会导致大约10-15%的性能损失,这就是为什么默认值为False的原因。
因此,我在代码中修改了以下内容,当用户尝试在刷新数据时尝试访问数据时,它现在不会崩溃:
# inside the connect method of the db_obj class
self.db_connection = cx.connect('connection string', threaded=True) # False by default
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.