Python中的cx_Oracle,生成器和线程

时间:2010-02-22 03:54:02

标签: python multithreading yield generator cx-oracle

当连接对象被不同的线程使用时,cx_Oracle游标的行为是什么?发电机如何影响这种行为?具体地说...

修改:原始示例功能不正确;子函数返回了一个生成器,yield没有直接在循环中使用。这澄清了finally何时执行(return之后),但仍然不回答是否可以使用游标,如果另一个线程开始使用创建游标的连接对象。它实际上似乎(至少在python 2.4中),try...finally yield会导致语法错误。

def Get()
  conn = pool.get()
  try:
    cursor = conn.cursor()
    cursor.execute("select * from table ...")
    return IterRows(cursor)
  finally:
    pool.put(conn)

def IterRows(cursor):
  for r in cursor:
    yield r

Get()是由多个线程调用的函数。使用threaded=False参数创建连接。

我想知道......

  1. 如果线程2出现并使用相同的连接对象,线程1的cursor对象是否仍然可用?如果没有,会发生什么?
  2. 我所看到的行为是cx_Oracle中的一个例外,它讨论了一个协议错误,然后是一个段错误。

1 个答案:

答案 0 :(得分:2)

请参阅the docsthreadsafety是,我引用,

  

目前2,表示线程   可以共享模块和连接,   但不是游标。

所以你的“游标池”构造(其中一个游标可能由不同的线程使用)似乎超出threadsafety级别。这不是共享连接的问题(因为你已经在连接的构造函数中正确地传递了threaded)但游标是正常的。您可能希望在第一次使用线程后将每个光标存储在threading.local中,以便每个线程都可以拥有自己的1光标“池”(不是键优化,但是:创建新光标是不是重型操作。)

回答你的问题2,finally子句在生成器对象(通过调用生成器函数Get构建)全部完成时执行 - 因为它正在引发StopIteration,或者因为它被垃圾收集(通常因为它的最后一次引用刚刚消失)。例如,如果呼叫者是:

def imthecaller():
  for i, row in enumerate(Get()):
    print i, row
    if i > 1: break
  # this is the moment the generators' finally-clause runs
  print 'bye'

finally在(最多)3行yield之后执行。