13

問題:

次のトレースバックが表示されますが、その意味や修正方法がわかりません。

Traceback (most recent call last):
  File "<string>", 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__()

状況:

処理するデータでいっぱいの SQL Server データベースがあります。multiprocessing モジュールを使用して作業を並列化し、コンピューターの複数のコアを利用しようとしています。私の一般的なクラス構造は次のとおりです。

  • MyManagerClass
    • これは、プログラムが開始されるメイン クラスです。
    • 2 つの multiprocessing.Queue オブジェクトを 1 つと 1 つ作成しますwork_queuewrite_queue
    • また、他のプロセスを作成して起動し、それらが終了するのを待ちます。
    • 注: これはmultiprocessing.managers.BaseManager() の拡張ではありません
  • MyReaderClass
    • このクラスは、SQL Server データベースからデータを読み取ります。
    • にアイテムを入れますwork_queue
  • MyWorkerClass
    • ここで作業処理が行われます。
    • からアイテムを取得し、work_queue完成したアイテムを に入れwrite_queueます。
  • MyWriterClass
    • このクラスは、処理されたデータを SQL Server データベースに書き戻す役割を担います。
    • からアイテムを取得しますwrite_queue

アイデアは、1 人のマネージャ、1 人のリーダー、1 人のライター、および多数のワーカーが存在するというものです。

その他の詳細:

私は stderr で 2 回トレースバックを取得するので、リーダーに対して 1 回、ライターに対して 1 回発生すると考えています。ワーカー プロセスは正常に作成されますが、KeyboardInterrupt を送信するまでそのまま待機しwork_queueます。

リーダーとライターの両方が、初期化時に作成されたデータベースへの独自の接続を持っています。

解決:

このソリューションにつながった回答と質問について、Mark と Ferdinand Beyer に感謝します。彼らは、Cursor オブジェクトが "pickle-able" ではないことを正しく指摘しました。これは、マルチプロセッシングがプロセス間で情報を渡すために使用する方法です。

私のコードの問題は、MyReaderClass(multiprocessing.Process)両方がメソッドMyWriterClass(multiprocessing.Process)でデータベースに接続されていることでした。__init__()これらの両方のオブジェクトを で作成し (つまり、init メソッドと呼びます) MyManagerClass、次に を呼び出しstart()ました。

したがって、接続オブジェクトとカーソル オブジェクトを作成し、それらを pickle 経由で子プロセスに送信しようとします。私の解決策は、接続オブジェクトとカーソル オブジェクトのインスタンス化を、子プロセスが完全に作成されるまで呼び出されない run() メソッドに移動することでした。

4

3 に答える 3

13

マルチプロセッシングは、プロセス間でオブジェクトを通信するためにピクルに依存しています。pyodbc 接続とカーソル オブジェクトはピクルできません。

>>> 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

「work_queueにアイテムを入れる」、何のア​​イテム?カーソルオブジェクトも渡される可能性はありますか?

于 2009-10-08T14:02:46.340 に答える
3

pyodbcには Python DB-APIスレッドセーフ レベル 1があります。これは、スレッドが接続を共有できないことを意味し、スレッドセーフではありません。

基になるスレッドセーフな ODBC ドライバーが違いを生むとは思いません。Pickling エラーで指摘されているように、これは Python コードにあります。

于 2014-10-30T02:50:08.710 に答える
3

エラーはpickleモジュール内で発生するため、どこかで DB-Cursor オブジェクトが pickle 化および unpickle 化されます (ストレージにシリアル化され、Python オブジェクトに再度シリアル化解除されます)。

pyodbc.Cursorそれは酸洗をサポートしていないと思います。とにかくカーソルオブジェクトを永続化しようとする必要があるのはなぜですか?

pickleワークチェーンのどこかで使用しているかどうか、または暗黙的に使用されているかどうかを確認してください。

于 2009-10-08T13:36:22.820 に答える