Python multitraitement et la base de données access avec pyodbc "n'est pas sans danger"?

Le Problème:

j'obtiens le traceback suivant et je ne comprends pas ce qu'il signifie Ou comment le réparer:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:Python26libmultiprocessingforking.py", line 342, in main
    self = load(from_parent)
  File "C:Python26libpickle.py", line 1370, in load
    return Unpickler(file).load()
  File "C:Python26libpickle.py", line 858, in load
    dispatch[key](self)
  File "C:Python26libpickle.py", line 1083, in load_newobj
    obj = cls.__new__(cls, *args)
TypeError: object.__new__(pyodbc.Cursor) is not safe, use pyodbc.Cursor.__new__()

la situation:

j'ai une base de données SQL Server pleine de données à traiter. J'essaie d'utiliser le module multiprocesseur pour paralléliser le travail et profiter des multiples noyaux de mon ordinateur. Ma structure générale de classe est comme suit:

  • MyManagerClass
    • C'est la classe principale, là où le programme commence.
    • il crée deux multiprocesseurs.Objets de file d'attente, un work_queue et write_queue
    • il crée et lance aussi les autres processus, puis attend qu'ils se terminent.
    • REMARQUE: c'est une extension du multiprocessing.gestionnaire.BaseManager ()
  • MyReaderClass
    • cette classe lit les données de la base de données SQL Server.
    • Il met des objets dans le work_queue.
  • MyWorkerClass
    • C'est ici que le traitement du travail a lieu.
    • On obtient les éléments de la work_queue et met les éléments terminés dans le write_queue.
  • MyWriterClass
    • cette classe est chargée d'écrire les données traitées retour à la base de données du serveur SQL.
    • On obtient les éléments de la write_queue.

L'idée est qu'il y aura un manager, un lecteur, un auteur, et de nombreux travailleurs.

d'Autres détails:

je reçois le traceback deux fois à stderr, donc je pense que ça arrive une fois pour le lecteur et une fois pour l'écrivain. Mes processus de travail sont bien créés, mais restez assis jusqu'à ce que j'envoie un KeyboardInterrupt parce qu'ils n'ont rien dans le work_queue.

le lecteur et le rédacteur ont leur propre connexion à la base de données, créée lors de l'initialisation.

Solution:

merci à Mark et Ferdinand Beyer pour leurs réponses et questions qui ont conduit à cette solution. Ils ont fait remarquer à juste titre que l'objet curseur n'est pas "pickle-able", qui est la méthode utilisée par multiprocessing pour transmettre des informations entre processus.

Le problème avec mon code était que MyReaderClass(multiprocessing.Process) et MyWriterClass(multiprocessing.Process) tous deux connectés à la base de données dans leur __init__() méthodes. J'ai créé ces deux objets (i.e. appelé leur méthode init) dans MyManagerClass, puis start().

donc il créerait la connexion et les objets de curseur, puis essaierait de les envoyer au processus enfant via pickle. Ma solution était de déplacer l'instanciation de la connexion et des objets curseur vers la méthode run (), qui n'est appelée que le processus de l'enfant est entièrement créé.

10
demandé sur tgray 2009-10-08 17:29:43

3 réponses

Le Multiprocessing s'appuie sur le décapage pour communiquer des objets entre les processus. La connexion pyodbc et les objets curseur ne peuvent pas être déplacés.

>>> cPickle.dumps(aCursor)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.5/copy_reg.py", line 69, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle Cursor objects
>>> cPickle.dumps(dbHandle)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.5/copy_reg.py", line 69, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle Connection objects

"Il met des objets dans le work_queue", quels éléments? Est-il possible que l'objet curseur soit passé aussi?

8
répondu Mark 2009-10-08 14:02:46

l'erreur est soulevée dans le pickle module, de sorte que quelque part votre objet DB-curseur se ramasse et se décompose (sérialisé au stockage et unserialisé à L'objet Python à nouveau).

je pense que pyodbc.Cursor ne supporte pas le décapage. Pourquoi essayer de persister l'objet curseur de toute façon?

Vérifiez si vous utilisez pickle quelque part dans votre chaîne de travail ou si elle est utilisée implicitement.

3
répondu Ferdinand Beyer 2009-10-08 13:36:22

pyodbc a Python DB-API threadsafety niveau 1. Cela signifie que les threads ne peuvent pas partager les connexions, et ce n'est pas threadsafe du tout.

Je ne pense pas que les pilotes ODBC sans fil sous-jacents fassent une différence. C'est dans le code Python comme noté par L'erreur de Pickling.

1
répondu user3389572 2014-10-30 02:50:08