Question

Quel est le comportement des curseurs cx_Oracle lorsque l'objet de connexion est utilisé par différents threads? Comment générateurs aurait une incidence sur ce comportement? Plus précisément ...

Modifier : La fonction d'exemple d'origine était incorrecte; un générateur a été retourné par une fonction secondaire, yield n'a pas été utilisé directement dans la boucle. Cela indique clairement quand il finally est exécuté (après return fait), mais ne répond toujours pas si un curseur peut être utilisé si un autre thread commence à utiliser la connexion objet le curseur a été créé à partir. Il semble en fait (en Python 2.4, au moins), avec try...finally yield provoque une erreur de syntaxe.

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() est une fonction appelée par plusieurs threads. Les connexions sont créées avec l'argument threaded=False.

Je me demande ...

  1. est thread 1 l'objet de la cursor encore utilisable si le thread 2 arrive et utilise le même objet de connexion? Dans le cas contraire, ce qui pourrait arriver?

Le comportement que je vois est une exception dans cx_Oracle parler d'une erreur de protocole, puis une suite segfault.

Était-ce utile?

La solution

Voir les docs : threadsafety est, et je cite,

  

Actuellement 2, ce qui signifie que les fils   peuvent partager le module et les connexions,   mais pas les curseurs.

Ainsi, votre « pool de curseurs » construire (où un curseur peut être utilisé par différents threads) semble être au-delà du niveau de threadsafety. Ce n'est pas une question de partage de connexions (c'est OK, puisque vous avez passé threaded correctement dans le constructeur de la connexion) mais les curseurs. Vous pouvez stocker chaque curseur dans threading.local après la première fois, un fil est utilisé, de sorte que chaque fil peut avoir son propre 1-curseur « pool » (pas une optimisation clé, cependant: faire un nouveau curseur n'est pas une lourde opération de service).

Wrt votre question 2, la clause finally exécute lorsque l'objet générateur (construit par un appel à votre fonction générateur Get) est fait - soit parce qu'il est élever StopIteration, ou parce qu'il est recueillie (généralement des déchets parce que la dernière référence à elle vient de loin). Si l'appelant par exemple est:

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'

la finally exécute après (au plus) 3 lignes ont été yielded.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top