Domanda

Qual è il comportamento di cursori cx_Oracle quando l'oggetto di connessione viene utilizzato da diversi thread? Come potrebbero influenzare generatori di questo comportamento? In particolare ...

Modifica : La funzione di esempio originale non era corretta; un generatore veniva restituito da una funzione secondaria, yield non è stato utilizzato direttamente nel ciclo. Questo chiarisce quando viene eseguita finally (dopo return fa), ma ancora non risponde se un cursore può essere utilizzato se un altro thread inizia a utilizzare la connessione oggetto il cursore è stato realizzato. In realtà sembra (in python 2.4, almeno), try...finally con yield causa un errore di sintassi.

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() è una funzione chiamata da più thread. I collegamenti vengono creati con l'argomento threaded=False.

Mi chiedo ...

  1. è thread 1 dell'oggetto cursor ancora utilizzabile se il thread 2 arriva e utilizza lo stesso oggetto di connessione? Se no, cosa potrebbe accadere?

Il comportamento che sto vedendo è un'eccezione in cx_Oracle parlando di un errore di protocollo, e poi un segfault segue.

È stato utile?

Soluzione

la documentazione : threadsafety è, e cito,

  

Attualmente 2, il che significa che le discussioni   può condividere il modulo e le connessioni,   ma non i cursori.

Così il vostro "pool di cursori" costruire (dove un cursore può essere utilizzato da diversi thread) sembra essere oltre il livello threadsafety. Non è una questione di condivisione delle connessioni (che è OK dal momento che hai passato threaded correttamente nel costruttore della connessione), ma i cursori. Si consiglia di memorizzare ogni cursore nella threading.local dopo la prima volta che un thread è usato, in modo che ogni thread può avere il proprio 1-cursor "pool" (non un'ottimizzazione chiave, però: fare un nuovo cursore non è un heavy- funzionamento dovere).

Wrt tua domanda 2, la clausola finally eseguito quando l'oggetto generatore (costruita da una chiamata alla funzione generatore Get) è tutto fatto - sia perché si tratta di sollevare StopIteration, o perché è in fase di garbage collection (in genere perché l'ultimo di riferimento ad esso è appena andato via). Per esempio se il chiamante è:

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'

il finally eseguito dopo (al massimo) 3 righe sono state yielded.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top