測試delphi支持的線程鎖的效率


TCriticalSection TMutex TSpinlock TMonitor

直接上圖:運行結果如下:

代碼如下

unit Unit5;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs
  ,System.Diagnostics, FMX.ScrollBox, FMX.Memo, FMX.Controls.Presentation,
  FMX.StdCtrls
  ,System.SyncObjs
  ,System.Threading;

type
  TForm5 = class(TForm)
    Multithreaded: TButton;
    btnSingleThreaded: TButton;
    MTwithlocking: TButton;
    MTwithmutex: TButton;
    MTwithTMonitor: TButton;
    MTwithspinlock: TButton;
    MTwithinterlocked: TButton;
    Memo1: TMemo;
    procedure btnSingleThreadedClick(Sender: TObject);
    procedure MultithreadedClick(Sender: TObject);
    procedure MTwithlockingClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure MTwithmutexClick(Sender: TObject);
    procedure MTwithTMonitorClick(Sender: TObject);
    procedure MTwithspinlockClick(Sender: TObject);
    procedure MTwithinterlockedClick(Sender: TObject);
  private
    { Private declarations }
      FTimer: TStopwatch;
      FValue:integer;
      FLock: TCriticalSection;
      FMutex: TMutex;
      FSpinlock: TSpinlock;
      procedure StartTimer;
      procedure StopTimer;
      procedure LogValue(const msg:string) ;
      procedure IncValue;
      procedure DecValue;
      procedure RunInParallel(task1, task2: TProc);
      procedure LockedIncValue;
      procedure LockedDecValue;
      procedure MutexIncValue;
      procedure MutexDecValue;
      procedure MonitorLockedIncValue;
      procedure MonitorLockedDecValue;
      procedure SpinlockIncValue;
      procedure SpinlockDecValue ;
      procedure InterlockedIncValue;
      procedure InterlockedDecValue;
  public
    { Public declarations }
  end;

var
  Form5: TForm5;

implementation

{$R *.fmx}
   uses System.DateUtils;//調用單元文件  必須D      MilliSecondsBetween(const ANow, AThen: TDateTime): Int64;
const
  CNumRepeat = 10000000;

procedure TForm5.btnSingleThreadedClick(Sender: TObject);
begin
{按順序先后執行,先執行完加法運算后,再執行減法去運算;結果應當為0;
如果是同時運行又會有啥結果呢?請看---->多線程Multithreaded按鈕}
  StartTimer;
  FValue := 0;
  IncValue;
  DecValue;
  StopTimer;
  LogValue('Single threaded');
end;

procedure TForm5.StartTimer;
begin
  FTimer := TStopwatch.StartNew;
end;

procedure TForm5.StopTimer;
begin
  FTimer.Stop;
end;

procedure TForm5.LogValue(const msg:string) ;
begin
   memo1.Lines.add(format('%S  %D [%d 毫秒]',[msg ,FValue,FTimer.ElapsedMilliseconds]));
end;
procedure TForm5.IncValue;
var
i,value:integer;
begin
    for i := 1 to CNumRepeat do begin
    value := FValue;
    FValue := value + 1;
  end;
end;


procedure TForm5.DecValue;
var
i,value:integer;
begin
    for i := 1 to CNumRepeat do
    begin
    value := FValue;
    FValue :=  FValue - 1;
    end;
end;

procedure TForm5.FormCreate(Sender: TObject);
begin
   MEMO1.Lines.Add('正確的答案應當是 0');
end;

procedure TForm5.RunInParallel(task1, task2: TProc);
var
tast: array[0..1] of iTask; //System.Threading

begin
   tast[0]:=TTASK.Run(task1) ;
   tast[1]:=TTASK.Run(task2) ;
   TTASK.WaitForAll(TAST);
end;


procedure TForm5.MultithreadedClick(Sender: TObject);
begin
  StartTimer;
  FValue := 0;
  RunInParallel(IncValue, DecValue);
  StopTimer;
  LogValue('Multithreaded');
    {執行結果如果是0,你可能也快中福利彩票特等獎了。
    在任何給定的時間,有數百個線程在不同的程序中運行,並且它們都在爭奪有限數量的CPU核心。
    名為同步並發,實則在同時在運行時,還要讓位給其它程序一定的時間,否則多任務的系統就
    變成單任務的系統,返回到WINDOWS 3.0時代了。正如司機帶着老婆和老媽去游玩,2檔上路;
    老婆和老媽同時要換檔:老婆要掛3檔,老媽掛到1檔。最終是掛到多少檔?
檔位就是共享的資源,多線程共享資源時,‘答案’是不確定的。
       ~
     (~.~)
       ~
    一定要同步,答案要確定,那又如何解決呢?請看往下看
    }
end;


procedure TForm5.MTwithlockingClick(Sender: TObject);
begin
  StartTimer;
  FValue := 0;
  FLock := TCriticalSection.Create; // ,System.SyncObjs
  {臨界區對象TCriticalSection,向系統申請對下面代碼的特權}
  try
   RunInParallel(LockedIncValue, LockedDecValue);
  finally
    FreeAndNil(FLock);  {用特權處理資源完畢,就得釋放特權,退還特權給系統!
     防止蹲着茅坑不拉SHI }
  end;
  StopTimer;
  LogValue('Critical section');

end;

procedure TForm5.LockedIncValue;
var
i,value:integer;
begin
    for i := 1 to CNumRepeat do
    begin
    FLock.Acquire;//占着廁所;
    value := FValue;
    FValue :=  FValue + 1;
    Flock.Release;////離開廁所,讓給下一位;
    end;

end;

procedure TForm5.LockedDecValue;
var
i,value:integer;
begin
    for i := 1 to CNumRepeat do
    begin
    FLock.Acquire;//占着廁所;
    value := FValue;
    FValue :=  FValue - 1;
    Flock.Release;離開廁所,讓給下一位;
    end;


end;

procedure TForm5.MTwithmutexClick(Sender: TObject);
begin
//互斥鎖 ,效率超級低,存在界面無響應問題 ,請繼續往下看
   StartTimer;
   FValue := 0;
  FMutex := TMutex.Create(nil, false, '');
  try
   RunInParallel(MutexIncValue, MutexDecValue);
   finally
    //FreeAndNil(FLock); //原來
   FreeAndNil(FMutex)
  end;

  StopTimer;
  LogValue('Mutex');
end;

procedure TForm5.MutexIncValue;
var
  i: integer;
  value: integer;
begin
  for i := 1 to CNumRepeat do begin
    FMutex.Acquire;
    value := FValue;
    FValue := value + 1;
    FMutex.Release;
  end;
end;

procedure TForm5.MutexDecValue;
var
  i: integer;
  value: integer;
begin
  for i := 1 to CNumRepeat do begin
    FMutex.Acquire;
    value := FValue;
    FValue := value - 1;
    FMutex.Release;
  end;
end;

procedure TForm5.MTwithTMonitorClick(Sender: TObject);
begin
{它比TCriticalSection更快更簡單(您不必創建單獨的對象)。只有在真正使用共享對象時才應該使用TMonitor,
這樣就可以直接鎖定它。它不使用臨界區,而是一種名為spinlock的改進思想。}
  StartTimer;
  FValue := 0;
  RunInParallel(MonitorLockedIncValue, MonitorLockedDecValue);
  StopTimer;
  LogValue('TMonitor');
end;

procedure TForm5.MonitorLockedIncValue;
var
  value: integer;
  i: Integer;
begin
  for i := 1 to CNumRepeat do begin
    System.TMonitor.Enter(Self);
    value := FValue;
    FValue := value + 1;
    System.TMonitor.Exit(Self);
  end;
end;

procedure Tform5.MonitorLockedDecValue;
var
value,i:integer;
begin
    for i := 1 to CNumRepeat do
    begin
      try
        system.TMonitor.Enter(SELF);
        VALUE:=fvalue;
        fvalue:=value-1;
        system.TMonitor.Exit(self);
      finally

      end;
    end;

end;


procedure TForm5.MTwithspinlockClick(Sender: TObject);
begin

{自旋鎖假定用它保護的代碼非常短,並且自旋鎖將被快速釋放。如果已經從另一個線程獲取了自旋鎖,則代碼首先嘗試主動等待或旋轉。代碼不是進入睡眠狀態,而是在緊密循環中運行,並不斷檢查自旋鎖是否可用。只有在一段時間后才發生這種情況,線程才會進入休眠狀態}

{TSpinLock是一個記錄,而不是一個對象,所以沒有必要釋放它。 您仍然需要創建它,因為一些數據在構造函數中初始化.

TSpinLock唯一的問題是它不是可重入的。 如果已經獲得自旋鎖的線程第二次調用Enter,則代碼將引發異常(如果已將True傳遞給構造函數)或阻塞。 但是,該實現提供了IsLocked和IsLockedByCurrentThread函數,您可以使用TSpinLock作為基函數來編寫可重入的自旋鎖。}
  StartTimer;
  FValue := 0;
  FSpinlock := TSpinLock.Create(false);
  RunInParallel(SpinlockIncValue, SpinlockDecValue);
  StopTimer;
  LogValue('Spinlock');
end;

procedure TForm5.SpinlockIncValue;
var
  i: integer;
  value: integer;
begin
  for i := 1 to CNumRepeat do
      begin
        FSpinlock.Enter;
        value := FValue;
        FValue := value + 1;
        FSpinlock.Exit;
      end;
end;

procedure TForm5.SpinlockDecValue;
var
i:integer;
value:integer;
 begin
    for I := 1 to CNumRepeat do
    begin
       Fspinlock.Enter;
       VALUE:=FVALUE;
       FVALUE:=VALUE-1;
       Fspinlock.Exit;
    end;

 end;

procedure TForm5.MTwithinterlockedClick(Sender: TObject);//互鎖操作,匯編指令級別
begin

{當共享數據足夠小並且您只需要遞增它或交換兩個值時,可以選擇在不鎖定的情況下執行此操作。所有現代處理器都實現了可以對存儲器位置進行簡單操作的指令,使得另一個處理器不會中斷正在進行的操作。
這些指令有時被稱為互鎖操作,而用它們編程的整個想法被稱為無鎖編程,或者有時稱為微鎖定。后一個術語實際上更合適,因為CPU確實做了一些鎖定。這種鎖定發生在匯編指令級別,因此比基於操作系統的鎖定(如關鍵部分)快得多。

}
  StartTimer;
  FValue := 0;
  RunInParallel(InterlockedIncValue, InterlockedDecValue);
  StopTimer;
  LogValue('Interlocked');
end;
procedure TForm5.InterlockedIncValue;
var
  i: integer;
begin
  for i := 1 to CNumRepeat do
    TInterlocked.Increment(FValue);
end;

procedure TForm5.InterlockedDecValue;
var
  i: integer;
begin
  for i := 1 to CNumRepeat do
    TInterlocked.Decrement(FValue);

end;


end.

原文地址:https://blog.csdn.net/qq_25439957/article/details/89431389

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM