Python中的cx_Oracle,生成器和线程

当连接对象被不同的线程使用时,cx_Oracle游标的行为是什么?发电机会如何影响这种行为?特别…

编辑:原始示例函数不正确;子函数返回一个生成器,在循环中没有直接使用yield.这澄清了何时执行(返回后),但仍然不回答是否可以使用游标,如果另一个线程开始使用创建游标的连接对象.它实际上似乎(在python 2.4中,至少),尝试…最终与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参数创建连接.

我在想…

>如果线程2出现并使用相同的连接对象,线程1的游标对象是否仍然可用?如果没有,会发生什么?

我所看到的行为是cx_Oracle中关于协议错误的异常,然后是段错误.

最佳答案 见
the docs:threadsafety是,我引用,

Currently 2, which means that threads
may share the module and connections,
but not cursors.

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

在你的问题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'

最后执行(最多)3行已经产生.

点赞