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
etwrite_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 lewrite_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éé.
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?
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.
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.