使用cx_Oracle的龙卷风背景任务

时间:2018-05-09 08:14:40

标签: python multithreading asynchronous tornado cx-oracle

我正在使用基础Bokeh框架运行Tornado服务器。

我需要服务器在某些时候刷新一些数据。这是通过使用Cx_Oracle从Oracle DB中提取行来完成的。

感谢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相关的函数(connect,fetch,...)。

基本上,这就是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类似于concurrent.futures.Future,但是   不是线程安全的(因此使用单线程更快   事件循环)。

总而言之,我认为我应该创建一个新线程来处理CX_Oracle操作。我可以使用Tornado执行此操作并继续使用PerodicCallback功能吗?如何将我的异步操作转换为线程安全?有什么办法呢?

PS:我正在使用Python 2.7

由于

1 个答案:

答案 0 :(得分:0)

解决了!

@Sraw是对的:它不应该导致崩溃。

解释fetch_data()正在使用cx Oracle Connection对象(self.db_connection),默认情况下它不是线程安全的。将threaded参数设置为True会将共享连接与互斥锁包装在一起,如Cx Oracle文档中所述:

  

thread参数应该是一个布尔表达式   指示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