「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > Python でマルチプロセッシング対応ログを実装する方法: キューベースのソリューション?

Python でマルチプロセッシング対応ログを実装する方法: キューベースのソリューション?

2024 年 11 月 3 日に公開
ブラウズ:844

  How to Implement Multiprocessing-Aware Logging in Python: A Queue-Based Solution?

Python でマルチプロセッシング対応ログを実装する方法

Python のマルチプロセッシングを使用すると、独立して実行される複数のプロセスを作成できます。ただし、ログ ファイルなどの共有リソースへのアクセスは、複数のプロセスが同時に書き込みを試行する可能性があるため、複雑になる可能性があります。

この問題を回避するために、Python マルチプロセッシング モジュールはモジュール レベルのマルチプロセッシング対応ログ機能を提供します。これにより、ロガーは一度に 1 つのプロセスのみが特定のファイル記述子に書き込まれるようにすることで、ログ メッセージの文字化けを防ぐことができます。

ただし、フレームワーク内の既存のモジュールはマルチプロセスを認識していない可能性があるため、代替ソリューションについては。 1 つのアプローチには、パイプ経由で親プロセスにログ メッセージを送信するカスタム ログ ハンドラーを作成することが含まれます。

このアプローチの実装は以下に示されています。

from logging.handlers import RotatingFileHandler
import multiprocessing, threading, logging, sys, traceback

class MultiProcessingLog(logging.Handler):
    def __init__(self, name, mode, maxsize, rotate):
        logging.Handler.__init__(self)

        # Set up the file handler for the parent process
        self._handler = RotatingFileHandler(name, mode, maxsize, rotate)
        
        # Create a queue to receive log messages from child processes
        self.queue = multiprocessing.Queue(-1)
        
        # Start a thread in the parent process to receive and log messages
        t = threading.Thread(target=self.receive)
        t.daemon = True
        t.start()

    def receive(self):
        while True:
            try:
                # Get a log record from the queue
                record = self.queue.get()
                
                # Log the record using the parent process's file handler
                self._handler.emit(record)
            # Exit the thread if an exception is raised
            except (KeyboardInterrupt, SystemExit):
                raise
            except EOFError:
                break
            except:
                traceback.print_exc(file=sys.stderr)

    def send(self, s):
        # Put the log record into the queue for the receiving thread
        self.queue.put_nowait(s)

    def _format_record(self, record):
        # Stringify any objects in the record to ensure that they can be sent over the pipe
        if record.args:
            record.msg = record.msg % record.args
            record.args = None
        if record.exc_info:
            dummy = self.format(record)
            record.exc_info = None
            
        return record

    def emit(self, record):
        try:
            # Format and send the log record through the pipe
            s = self._format_record(record)
            self.send(s)
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)

    def close(self):
        # Close the file handler and the handler itself
        self._handler.close()
        logging.Handler.close(self)

このカスタム ログ ハンドラーを使用すると、フレームワーク内のモジュール自体がマルチプロセッシングを認識することなく、標準のロギング方法を使用できるようになります。ログ メッセージは子プロセスからパイプ経由で親プロセスに送信され、文字化けせずにログ ファイルに正しく書き込まれます。

最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3