TParallel.For
ดำเนินการประมวลผลเหตุการณ์การวนซ้ำแบบเธรด แต่ตัวมันเองเป็นวิธีการบล็อก ดังนั้นคุณจะต้องระมัดระวังในการซิงโครไนซ์หากคุณเริ่มจากเธรดหลัก
การใช้ TThread.Queue
ทำงานได้อย่างปลอดภัย แต่อย่างที่คุณสังเกตเห็นแล้วว่า กิจกรรมที่อยู่ในคิวทั้งหมดจะได้รับการประมวลผล หลังจาก TParallel.For
เสร็จสิ้น - อันที่จริง หลังจากออกจากเมธอดและกลับสู่สถานะไม่ได้ใช้งาน
การใช้ TThread.Synchronize
จะทำให้เกิด การล็อกตาย หากคุณใช้ในเหตุการณ์การวนซ้ำและเริ่มต้น TParallel.For
จากเธรดหลัก
นี่เป็นแอปพลิเคชั่นเล็กๆ น้อยๆ ที่แสดงความแตกต่างในการใช้งาน
CopyFiles
ParallelCopyFiles
AsyncCopyFiles
โทร CopyFiles
จากงาน
AsyncParallelCopyFiles
โทร ParallelCopyFiles
จากงาน
และฉันคิดว่า AsyncParallelCopyFiles
คือสิ่งที่คุณกำลังมองหา
ภายในวิธีการ Async...
คุณสามารถใช้ TThread.Synchronize
- ถ้าคุณไม่รองานภายในเธรดหลัก
unit Form.Main;
interface
uses
System.IOUtils,
System.Threading,
System.Types,
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TLogMsg = record
private
FMsg: string;
FThreadID: Cardinal;
FOccurred: TDateTime;
public
class operator implicit( a: string ): TLogMsg;
class operator implicit( a: TLogMsg ): string;
constructor Create( const AMsg: string );
function ToString: string;
property Msg: string read FMsg;
property ThreadID: Cardinal read FThreadID;
property Occurred: TDateTime read FOccurred;
end;
type
TForm1 = class( TForm )
ListBox1: TListBox;
RadioGroup1: TRadioGroup;
Button1: TButton;
procedure Button1Click( Sender: TObject );
private
FTask: ITask;
procedure ThreadSafeLog( ALogMsg: TLogMsg );
public
procedure CopyFiles( AFiles: TStringDynArray; ADestPath: string; Overwrite: Boolean );
procedure ParallelCopyFiles( AFiles: TStringDynArray; ADestPath: string; Overwrite: Boolean );
function AsyncCopyFiles( AFiles: TStringDynArray; ADestPath: string; Overwrite: Boolean; ACallback: TThreadProcedure ): ITask;
function AsyncParallelCopyFiles( AFiles: TStringDynArray; ADestPath: string; Overwrite: Boolean; ACallback: TThreadProcedure ): ITask;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
// *** ATTENTION ***
// ParallelCopyFiles will cause a dead lock without USE_QUEUE
// but you still can try yourself ...
//
{$DEFINE USE_QUEUE}
//
// *****************
procedure TForm1.ThreadSafeLog( ALogMsg: TLogMsg );
begin
{$IFDEF USE_QUEUE}
TThread.Queue
{$ELSE}
TThread.Synchronize
{$ENDIF}
( nil,
procedure
begin
ListBox1.Items.Add( ALogMsg );
end );
end;
procedure TForm1.CopyFiles( AFiles: TStringDynArray; ADestPath: string; Overwrite: Boolean );
var
LSource, LDestination: string;
begin
ThreadSafeLog( 'CopyFiles - ENTER' );
for LSource in AFiles do
begin
LDestination := TPath.Combine( ADestPath, TPath.GetFileName( LSource ) );
ThreadSafeLog( 'Copy ' + LSource );
TFile.Copy( LSource, LDestination, Overwrite );
end;
ThreadSafeLog( 'CopyFiles - EXIT' );
end;
procedure TForm1.ParallelCopyFiles( AFiles: TStringDynArray; ADestPath: string; Overwrite: Boolean );
begin
ThreadSafeLog( 'ParallelCopyFiles - ENTER' );
TParallel.&For( Low( AFiles ), High( AFiles ),
procedure( AIndex: Integer )
var
LSource, LDestination: string;
begin
LSource := AFiles[AIndex];
LDestination := TPath.Combine( ADestPath, TPath.GetFileName( LSource ) );
ThreadSafeLog( 'Copy ' + LSource );
TFile.Copy( LSource, LDestination, Overwrite );
end );
ThreadSafeLog( 'ParallelCopyFiles - EXIT' );
end;
function TForm1.AsyncCopyFiles( AFiles: TStringDynArray; ADestPath: string; Overwrite: Boolean; ACallback: TThreadProcedure ): ITask;
begin
ThreadSafeLog( 'AsyncCopyFiles - ENTER' );
Result := TTask.Run(
procedure
begin
CopyFiles( AFiles, ADestPath, Overwrite );
TThread.Synchronize( nil, ACallback );
end );
ThreadSafeLog( 'AsyncCopyFiles - EXIT' );
end;
function TForm1.AsyncParallelCopyFiles( AFiles: TStringDynArray; ADestPath: string; Overwrite: Boolean; ACallback: TThreadProcedure ): ITask;
begin
ThreadSafeLog( 'AsyncParallelCopyFiles - ENTER' );
Result := TTask.Run(
procedure
begin
ParallelCopyFiles( AFiles, ADestPath, Overwrite );
TThread.Synchronize( nil, ACallback );
end );
ThreadSafeLog( 'AsyncParallelCopyFiles - EXIT' );
end;
procedure TForm1.Button1Click( Sender: TObject );
var
LFiles: TStringDynArray;
LDestPath: string;
begin
ListBox1.Clear; // Clear the log destination
LFiles := TDirectory.GetFiles( TPath.GetDocumentsPath, '*.*' );
LDestPath := TPath.Combine( TPath.GetDocumentsPath, '_COPYTEST_' );
TDirectory.CreateDirectory( LDestPath );
case RadioGroup1.ItemIndex of
0:
CopyFiles( LFiles, LDestPath, True );
1:
ParallelCopyFiles( LFiles, LDestPath, True );
2:
begin
Button1.Enabled := False;
AsyncCopyFiles( LFiles, LDestPath, True,
procedure
begin
Button1.Enabled := True;
end );
end;
3:
begin
Button1.Enabled := False;
AsyncParallelCopyFiles( LFiles, LDestPath, True,
procedure
begin
Button1.Enabled := True;
end );
end;
end;
end;
{ TLogMsg }
constructor TLogMsg.Create( const AMsg: string );
begin
FMsg := AMsg;
FThreadID := TThread.CurrentThread.ThreadID;
FOccurred := Now;
end;
class operator TLogMsg.implicit( a: string ): TLogMsg;
begin
Result := TLogMsg.Create( a );
end;
class operator TLogMsg.implicit( a: TLogMsg ): string;
begin
Result := a.ToString;
end;
function TLogMsg.ToString: string;
begin
Result := Format( '$%8.8x [%s] %s', [FThreadID, FormatDateTime( 'hh:nn:ss.zzz', FOccurred ), FMsg] );
end;
end.
อัปเดตแล้ว
ฉันเพิ่งขยายข้อความบันทึกด้วยข้อมูลเพิ่มเติมเกี่ยวกับเธรดและเวลาที่เกิดขึ้นของข้อความ
person
Sir Rufo
schedule
10.03.2015
TThread.Queue
ถูกดำเนินการหลังจากเธรดเสร็จสิ้นTThread.Synchronize
คือสิ่งที่ฉันต้องการสำหรับการนำไปใช้งาน - person Aid Vllasaliu   schedule 10.03.2015TThread.Queue(nil, Aproc);
ควรใช้งานได้ - person LU RD   schedule 10.03.2015TThread.Queue
โดยnil
ที่กำหนดให้กับพารามิเตอร์แรกใช้งานได้ แต่หลังจากอ่านเพิ่มเติมเกี่ยวกับสิ่งนี้ ปรากฎว่าโค้ดใดๆ ภายในTThread.Queue
จะถูกดำเนินการหลังจากเธรดเสร็จสิ้น ฉันไม่ต้องการสิ่งนั้น ฉันต้องบันทึกทุกขั้นตอนของกระบวนการในขณะที่มันเกิดขึ้น ดังนั้นเหตุใดTThread.Synchronize
จึงเหมาะสมกว่า - person Aid Vllasaliu   schedule 10.03.2015TThread.Queue()
จะถูกดำเนินการเมื่อใดก็ตามที่เธรดหลักเข้ามาดำเนินการ มันไม่เกี่ยวอะไรกับอายุการใช้งานของเธรดที่เรียกQueue()
เธรดอาจยังคงทำงานอยู่ หรืออาจยุติลงแล้ว ประเด็นคือQueue()
อะซิงโครนัส มันจะออกทันทีและไม่รอให้โค้ดทำงานTThread.Synchronize()
จะรอ - person Remy Lebeau   schedule 10.03.2015TParallel.For
เพียงเพราะเป็นการดำเนินการบล็อก และรอจนกว่าทุกอย่างจะเสร็จสิ้นTThread.Sychronize
ควรทำให้เกิดการหยุดชะงักที่นี่ - person Sir Rufo   schedule 10.03.2015log()
เพียงเพิ่มบรรทัดของสตริงในTMemo
- person Aid Vllasaliu   schedule 10.03.2015Form1.Memo1.....
ของพวกเขาด้วยวิธีLog()
ของฉันแล้ว - person Aid Vllasaliu   schedule 11.03.2015