Python multitraitement et l'access à la database avec pyodbc "n'est pas sûr"?

Le problème:

Je reçois la trace suivante et ne comprends pas ce que cela signifie ou comment le réparer:

Traceback (most recent call last): File "<ssortingng>", line 1, in <module> File "C:\Python26\lib\multiprocessing\forking.py", line 342, in main self = load(from_parent) File "C:\Python26\lib\pickle.py", line 1370, in load return Unpickler(file).load() File "C:\Python26\lib\pickle.py", line 858, in load dispatch[key](self) File "C:\Python26\lib\pickle.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 database SQL Server pleine de données à traiter. J'essaie d'utiliser le module multi-traitement pour paralléliser le travail et tirer parti des multiples cœurs de mon ordinateur. Ma structure de class générale est la suivante:

  • MyManagerClass
    • C'est la class principale, où le programme commence.
    • Il crée deux objects multiprocessing.Queue, une work_queue et une write_queue
    • Il crée et lance également les autres process, puis attend leur fin.
    • NOTE: ce n'est pas une extension de multiprocessing.managers.BaseManager ()
  • MyReaderClass
    • Cette class lit datatables de la database SQL Server.
    • Il met des éléments dans la work_queue .
  • MyWorkerClass
    • C'est là que se déroule le traitement du travail.
    • Il récupère les éléments de work_queue et place les éléments complétés dans write_queue .
  • MyWriterClass
    • Cette class est chargée d'écrire datatables traitées dans la database SQL Server.
    • Il obtient des éléments de write_queue .

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

Autres détails:

Je reçois le retraçage deux fois dans stderr, donc je pense que cela arrive une fois pour le lecteur et une fois pour l'écrivain. Mes process de travail sont bien créés, mais restons là jusqu'à ce que j'envoie un KeyboardInterrupt car ils n'ont rien dans la work_queue .

Le lecteur et l'écrivain ont tous deux leur propre connection à la database créée à l'initialisation.

Solution:

Merci à Mark et Ferdinand Beyer pour leurs réponses et leurs questions qui ont conduit à cette solution. Ils ont souligné à juste titre que l'object Cursor n'est pas "pickle-able", qui est la méthode utilisée par le multitraitement pour transmettre des informations entre les process.

Le problème avec mon code était que MyReaderClass(multiprocessing.Process) et MyWriterClass(multiprocessing.Process) tous deux connectés à la database dans leurs __init__() . J'ai créé ces deux objects (c'est-à-dire appelé leur méthode init) dans MyManagerClass , puis appelé start() .

Il créera donc les objects de connection et de slider, puis essaiera de les envoyer au process fils via le pickle. Ma solution consistait à déplacer l'instanciation des objects connection et cursor vers la méthode run (), qui n'est pas appelée tant que le process enfant n'est pas entièrement créé.

Le multitraitement repose sur le décapage pour communiquer des objects entre les process. La connection pyodbc et les objects de slider ne peuvent pas être décapé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 éléments dans la queue", quels sont les éléments? Est-il possible que l'object slider soit également passé?

L'erreur est levée dans le module pickle , donc quelque part votre object DB-Cursor est décapé et décoché (sérialisé pour le stockage et non sérialisé à l'object Python à nouveau).

Je suppose que pyodbc.Cursor ne supporte pas le décapage. Pourquoi devriez-vous essayer de conserver l'object slider de toute façon?

Vérifiez si vous utilisez du pickle quelque part dans votre string de travail ou si vous l'utilisez implicitement.

pyodbc a le niveau de security de threads Python DB-API 1 . Cela signifie que les threads ne peuvent pas partager les connections, et ce n'est pas du tout sûr pour les threads.

Je ne pense pas que les pilotes ODBC thread-safe sous-jacents font une différence. C'est dans le code Python comme indiqué par l'erreur Pickling.