Python 中的 cx_Oracle、生成器和线程

Ric*_*eur 5 python multithreading cx-oracle yield generator

当连接对象被不同线程使用时,cx_Oracle 游标的行为是什么?生成器将如何影响这种行为?具体来说...

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

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
Run Code Online (Sandbox Code Playgroud)

Get()是一个被多个线程调用的函数。连接是通过threaded=False参数创建的。

我在想...

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

我看到的行为是 cx_Oracle 中谈论协议错误的异常,然后出现段错误。

Ale*_*lli 2

请参阅文档threadsafety是,我引用,

当前为 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'
Run Code Online (Sandbox Code Playgroud)

finally(最多)3 行被编辑后执行yield