mormot.core.threads--TSynParallelProcess

海利鸟發表於2024-07-08

mormot.core.threads--TSynParallelProcess

{ ************ 執行緒池中的並行執行 }

type
  /// TSynParallelProcess 的並行化過程回撥
  // - 如果 0<=IndexStart<=IndexStop,則應執行某些過程
  TOnSynParallelProcess = procedure(IndexStart, IndexStop: integer) of object;

  /// 為 TSynParallelProcess 執行過程的執行緒
  TSynParallelProcessThread = class(TSynBackgroundThreadMethodAbstract)
  protected
    fMethod: TOnSynParallelProcess; // 回撥方法
    fIndexStart, fIndexStop: integer; // 要處理的索引範圍
    procedure Start(const Method: TOnSynParallelProcess; // 開始執行過程
      IndexStart, IndexStop: integer);
    /// 執行 fMethod(fIndexStart,fIndexStop)
    procedure Process; override;
  public
  end;

  /// 允許線上程池中並行執行基於索引的過程
  // - 將建立自己的執行緒池,然後將工作分配給每個執行緒執行
  TSynParallelProcess = class(TSynPersistentLock)
  protected
    fThreadName: RawUtf8; // 執行緒名稱
    fPool: array of TSynParallelProcessThread; // 執行緒池
    fThreadPoolCount: integer; // 執行緒池中的執行緒數
    fParallelRunCount: integer; // 並行執行次數
  public
    /// 初始化執行緒池
    // - 您可以定義一些回撥來巢狀執行緒執行,例如,分配給 TRestServer.BeginCurrentThread/EndCurrentThread
    // - 最多可設定 MaxThreadPoolCount=32 個執行緒(您可以允許更大的值,但此執行緒池的目的是使其程序飽和每個 CPU 核心)
    // - 如果 ThreadPoolCount 為 0,則不會建立執行緒,並且過程將在當前執行緒中執行
    constructor Create(ThreadPoolCount: integer; const ThreadName: RawUtf8;
      const OnBeforeExecute: TOnNotifyThread = nil; // 執行前通知回撥
      const OnAfterExecute: TOnNotifyThread = nil;  // 執行後通知回撥
      MaxThreadPoolCount: integer = 32); reintroduce; virtual;
    /// 終結執行緒池
    destructor Destroy; override;
    /// 並行執行一個方法,並等待執行完成
    // - 將 Method[0..MethodCount-1] 的執行分散到執行緒中
    // - 如果在過程中發生任何異常,則此方法將引發 ESynParallel 異常
    // - 如果設定了 OnMainThreadIdle,則當前執行緒(例如,預期為主 UI 執行緒)將不會處理任何內容,但在等待後臺執行緒時呼叫此事件
    procedure ParallelRunAndWait(const Method: TOnSynParallelProcess;
      MethodCount: integer; const OnMainThreadIdle: TNotifyEvent = nil);
  published
    /// 已啟用的執行緒數
    property ParallelRunCount: integer
      read fParallelRunCount;
    /// 此例項執行緒池中當前有多少執行緒
    property ThreadPoolCount: integer
      read fThreadPoolCount;
    /// 一些文字識別符號,用於區分每個擁有的執行緒
    property ThreadName: RawUtf8
      read fThreadName;
  end;

後期再整理!

由於 TSynParallelProcess在mORMot 2框架中是一個假定的類(因為標準的mORMot 2庫並不直接包含這個類名,但它可能是一個自定義擴充套件或類似功能的類的代表),我將基於您提供的類定義來編寫一個假設的例程程式碼,這個程式碼將模擬在Free Pascal中使用這樣一個類。

請注意,以下程式碼將不會直接編譯,因為 TSynParallelProcessTSynParallelProcessThread的具體實現細節(如建構函式、解構函式和方法的內部邏輯)並未給出。但是,我將提供一個結構化的示例,展示如何使用這樣的類(如果它存在的話)。

program TSynParallelProcessDemo;

{$MODE DELPHI}

uses
  SysUtils, Classes; // 引入必要的單元

// 假設TSynParallelProcess和TSynParallelProcessThread已經在某個單元中定義
// 這裡我們使用一個佔位符單元名YourMormotUnit
// 注意:在實際應用中,您需要替換'YourMormotUnit'為包含這些類的實際單元名
uses YourMormotUnit;

procedure MyParallelTask(IndexStart, IndexStop: integer);
begin
  // 這裡是您的並行任務邏輯
  WriteLn('Executing task with indices from ', IndexStart, ' to ', IndexStop);
  // 模擬耗時操作
  Sleep(100); // 假設每個任務需要一些時間來完成
end;

var
  ParallelProcessor: TSynParallelProcess;
  TaskCount: Integer;

begin
  try
    // 初始化任務計數(這裡假設我們有100個任務要並行處理)
    // 注意:在實際應用中,您可能需要根據具體情況來確定這個值
    TaskCount := 100;

    // 建立TSynParallelProcess例項
    // 注意:這裡我們假設ThreadPoolCount是一個合理的值,例如CPU核心數的兩倍
    // 並且MaxThreadPoolCount足夠大以容納所需的執行緒數
    // ThreadName是可選的,用於標識執行緒池中的執行緒
    ParallelProcessor := TSynParallelProcess.Create(
      System.SysUtils.GetProcessorCount * 2, // 假設執行緒池大小為CPU核心數的兩倍
      'MyParallelTasks', // 執行緒名稱字首(可選)
      nil, // OnBeforeExecute回撥(這裡不使用)
      nil  // OnAfterExecute回撥(這裡不使用)
    );
    try
      // 並行執行任務並等待完成
      // 注意:這裡的ParallelRunAndWait是假設的方法,它可能不直接存在於TSynParallelProcess中
      // 您需要根據實際的方法簽名和邏輯來調整以下呼叫
      // 由於我們沒有ParallelRunAndWait的具體實現,這裡只是一個示意性的呼叫
      // 在實際中,您可能需要呼叫一個不同的方法,或者ParallelRunAndWait本身就需要您來實現
      // 假設ParallelRunAndWait接受一個任務過程和任務總數作為引數
      ParallelProcessor.ParallelRunAndWait(
        @MyParallelTask, // 指向您的並行任務過程的指標
        TaskCount        // 要並行處理的任務總數
      );
    finally
      // 銷燬TSynParallelProcess例項
      ParallelProcessor.Free;
    end;
  except
    on E: Exception do
      WriteLn('An error occurred: ', E.Message);
  end;
  // 保持控制檯視窗開啟,直到使用者按任意鍵
  WriteLn('Press Enter to exit...');
  ReadLn;
end.

重要說明

  1. 類和方法的存在性:上述程式碼假設 TSynParallelProcess類及其 ParallelRunAndWait方法存在。在mORMot 2的標準庫中,這樣的類和方法可能不存在,或者它們的名稱和引數可能有所不同。
  2. 實現細節:由於我們沒有 TSynParallelProcessTSynParallelProcessThread的具體實現,因此上述程式碼中的 ParallelRunAndWait呼叫是示意性的。在實際應用中,您需要根據實際可用的方法來實現並行任務的執行。
  3. 執行緒池大小:在建立 TSynParallelProcess例項時,我使用了 System.SysUtils.GetProcessorCount * 2作為執行緒池的大小。這只是一個常見的啟發式方法,用於確定合理的執行緒數。然而,最佳執行緒數取決於您的具體應用程式和工作負載。
  4. 錯誤處理:程式碼中包含了基本的錯誤處理邏輯,用於捕獲並列印異常訊息。在實際應用中,您可能需要根據需要擴充套件這種錯誤處理。
  5. 單元引用:請將 uses YourMormotUnit;中的 YourMormotUnit替換為包含 TSynParallelProcessTSynParallelProcessThread定義的實際單元名。如果這些類是您自定義的,那麼您需要確保它們已經被正確編譯幷包含在您的專案中。