問題:
次のトレースバックが表示されますが、その意味や修正方法がわかりません。
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_queue
。write_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() メソッドに移動することでした。