Pergunta

Qual é o comportamento dos cursores cx_oracle quando o objeto de conexão é usado por threads diferentes? Como os geradores afetariam esse comportamento? Especificamente...

Editar: A função de exemplo original estava incorreta; Um gerador estava sendo devolvido por uma sub -função, yield não foi usado diretamente no loop. Isso esclarece quando finally é executado (depois return faz), mas ainda não responde se um cursor pode ser usado se outro thread começar a usar o objeto de conexão de onde o cursor foi criado. Na verdade, parece (no Python 2.4, pelo menos), try...finally com yield causa um erro de sintaxe.

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() é uma função chamada por vários threads. As conexões são criadas com o threaded=False argumento.

Estou me perguntando ...

  1. É o thread 1 cursor Objeto ainda utilizável se o Thread 2 aparecer e usar o mesmo objeto de conexão? Caso contrário, o que pode acontecer?

O comportamento que estou vendo é uma exceção no CX_oracle falando sobre um erro de protocolo e, em seguida, segue -se um segfault.

Foi útil?

Solução

Ver os documentos: threadsafety é, e eu cito,

Atualmente 2, o que significa que os threads podem compartilhar o módulo e as conexões, mas não os cursores.

Portanto, sua construção "pool de cursores" (onde um cursor pode ser usado por diferentes threads) parece estar além do threadsafety nível. Não é uma questão de compartilhar conexões (tudo bem desde que você passou threaded corretamente no construtor da conexão), mas cursores. Você pode querer armazenar cada cursor em threading.local Após a primeira vez, um thread o usou, para que cada thread possa ter seu próprio "pool" de 1 cursor (porém, não é uma otimização de chave: fazer um novo cursor não é uma operação pesada).

Wrt sua pergunta 2, o finally A cláusula é executada quando o objeto do gerador (construído por uma chamada para a função do seu gerador Get) está tudo pronto - porque está criando StopIteration, ou porque está sendo coletado com lixo (normalmente porque a última referência a ele acabou de desaparecer). Por exemplo, se o chamador for:

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'

a finally executa após (no máximo) 3 linhas foram yielded.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top