multiprocessing.Pool を使用して、(D&D 5e での戦闘の) シミュレーション用に書いた Python コードを並列化しています。ただし、次のエラーが表示されますcan't pickle _thread.RLock objects
。私はいくつかの調査を行いましたが、問題は私のシミュレーションが (logging
モジュールからの) ロガーを持つオブジェクトを使用していることにあるようです。シミュレーションの単一プロセス実行のログ記録を引き続きサポートしたい (デバッグや出力のチェックができるようにするため) が、複数プロセス実行のログ記録サポートはあまり重要ではありません。通常、実況は必要ありません。ここでロギングが問題にならないようにコードをリファクタリングするにはどうすればよいですか (複数のプロセスがある場合にロギングを無効にする、マルチプロセッシングが受け入れる方法でロギングを実装するなど)。
私のシミュレーションクラスからのいくつかのコード:
def process_run(self, num): # pylint: disable=unused-argument
"""
The method given to an individual process to do work. Run only once per process so we don't need to reset anything
:param num: which iteration of the loop am I
:return:
"""
self._encounter.run()
return self._encounter.get_stats()
def mp_run(self, n=1000, p=None):
"""
Run the Encounter n times (using multiprocessing), then print the results
:param n: number of times to run the encounter
:param p: number of processes to use. If None, use max number of processes
:return: aggregate stats
"""
if p:
pool = Pool(p) # use user-specified number of processes
else:
pool = Pool() # use max number of processes as user didn't specify
for result in pool.imap_unordered(self.process_run, range(n)):
self.update_stats(result)
pool.close()
pool.join()
self.calculate_aggregate_stats(n)
self.print_aggregate_stats()
return self._aggregate_stats
ロギングを使用する一部のコード (各シミュレーションがインスタンスを持つ Encounter クラスから):
self.get_logger().info("Round %d", self.get_round())
unconscious = [comb.get_name() for comb in self.get_combatants() if comb.has_condition("unconscious")]
if unconscious:
self.get_logger().info("Unconscious: %s", str(unconscious))
dead = [comb.get_name() for comb in self.get_combatants() if comb.has_condition("dead")]
if dead:
self.get_logger().info("Dead: %s", str(dead))
さらにコード例が必要な場合は、お知らせください。