Multithreading 如果我从一个单独的线程调用代码,为什么代码运行得较慢?

Multithreading 如果我从一个单独的线程调用代码,为什么代码运行得较慢?,multithreading,delphi,Multithreading,Delphi,我刚刚使用Delphi的TThread类向应用程序添加了线程。线程调用一个函数,比较两个文件并打印它们之间不同的位。在我介绍线程之前,应用程序可以完成这个过程,并在大约1-2秒内将输出打印到一个300KB的文件上。在引入线程检查后,同一文件可能需要30-45秒,并导致50%的CPU峰值(AMD Phenom II Triple Core),之前您没有注意到峰值 线程正在执行的代码是: procedure TForm1.CompareFiles(fil1, fil2 : ansistring; s

我刚刚使用Delphi的TThread类向应用程序添加了线程。线程调用一个函数,比较两个文件并打印它们之间不同的位。在我介绍线程之前,应用程序可以完成这个过程,并在大约1-2秒内将输出打印到一个300KB的文件上。在引入线程检查后,同一文件可能需要30-45秒,并导致50%的CPU峰值(AMD Phenom II Triple Core),之前您没有注意到峰值

线程正在执行的代码是:

procedure TForm1.CompareFiles(fil1, fil2 : ansistring; sg : TStringGrid; option : integer; progb : TProgressBar);
var
forg, fpat : file;
byteorg, bytepat : Byte;
byteorgc,bytepatc : ansistring;
arrby : Array Of ansistring;
arrpos : Array Of ansistring;
i,x : integer;
begin

if CRCAdlerGenFile(fil1,1) <> CRCAdlerGenFile(fil2,1) then //Only Run if files arn't same
begin
sg.Cols[0].Clear;
sg.Cols[1].Clear;
i := 0;
x := 0;

AssignFile(forg,fil1);
FileMode := fmOpenRead;
Reset(forg,1);
AssignFile(fpat,fil2);
FileMode := fmOpenRead;
Reset(fpat,1);

//Set Progress Bar
progb.Min := 0;
progb.Max := FileSize(forg);

while NOT eof(forg) do
begin
BlockRead(forg,byteorg,1);
BlockRead(fpat,bytepat,1);
Progb.Position := Progb.Position + 1;
byteorgc := IntToHex(byteorg,2);
bytepatc := IntToHex(bytepat,2);
if byteorg <> bytepat then
begin
x := x + 1;
SetLength(arrby,x);
SetLength(arrpos,x);
arrpos[i] := IntToStr(FilePos(forg));
arrby[i] := bytepatc;
i := i + 1;
end;
end;

CloseFile(forg);
CloseFile(fpat);


case option of
0 : begin //Base 2
    for I := 0 to (Length(arrpos) - 1) do
    begin
    arrpos[i] := IntToBin(StrToInt(arrpos[i]),8);
    end;
    end;

1 : ; //Base 10

2 :  begin //Base 16
    for I := 0 to (Length(arrpos) - 1) do
      begin
        arrpos[i] := IntToHex(StrToInt(arrpos[i]),1);
      end;
    end;

3 : begin //Append $
    for I := 0 to (Length(arrpos) - 1) do
    begin
    arrpos[i] := '$'+IntToHex(StrToInt(arrpos[i]),1);
    end;
    end;

4 : begin //Append 0x
    for I := 0 to (Length(arrpos) - 1) do
    begin
    arrpos[i] := '0x'+IntToHex(StrToInt(arrpos[i]),1);
    end;
    end;
end;


Sg.RowCount := Length(arrpos);
for I := 0 to (Length(arrpos) - 1) do
begin
  sg.Cells[0,i] := arrpos[i];
  sg.Cells[1,i] := arrby[i];
end;

if sg.RowCount >= 16 then
sg.DefaultColWidth := 222
else
sg.DefaultColWidth := 231;
end;

end;
同步程序

procedure TCompareFilesThread.SProgBarNext;
begin
Form1.ProgressBar1.Position := Form1.ProgressBar1.Position + 1;
end;

此代码正在其他线程中运行?一个明显的问题是使用VCL控件。VCL不是线程安全的,尝试从主线程外部更新VCL属性必然会导致问题。这需要进行大量的重构。线程例程的要点是执行计算。您不应该传入TStringGrid,也不应该更新进度条


看看从工作线程与主线程交互的正确方法。这需要一些工作,但最终会更快更干净。

Delphi中的默认线程优先级是tpLower,这可能是它运行速度比预期慢的原因。其他人正确地指出,这段代码非常危险。甚至不要考虑在Delphi中从辅助线程中更新UI控件。p> 在我对上一个问题的回答中,我写道:“最后要注意的是,
TStringGrid
是一个VCL控件。你不能从你创建的这个新线程对它做任何事情(不管你最终如何创建它).grid控件的所有操作都需要从主线程执行。使用
TThread.Synchronize
TThread.Queue
将任何VCL操作转移到主线程上。”我看你没有注意到这个建议。你访问文件的方式确实是性能不好的根源:我建议你不要为两个文件读取单字节块,你可以读取大的块(4K或更多),然后根据需要比较每个字节,并且,不要将字节转换为字符串来执行比较。。。只需比较字节!!平面,我惊讶它运行的原因是它与VCL的交互,尤其是字符串网格。但正如你之前被告知的那样,阅读发布的链接,思考这些链接与你的情况之间的关系。除非你能做到,否则我们帮不了你。@offplatline:5kB?您的文件很可能以4kb的块存储在磁盘上。最好是读取4KB的倍数:如果您不喜欢4KB,请使用8KB或16KB。@平台外:分块读取文件是一种必需的基本编码,我不喜欢称之为优化。一次读取一个字节的文件几乎需要相同的编码工作。您能否解释一下,在一个有空闲CPU周期的系统上,较低的线程优先级如何会导致性能下降90%以上?
procedure TCompareFilesThread.SyncGrid;
begin
  form1.StringGrid2.RowCount := x;

    if x >= 16 then
      form1.StringGrid2.DefaultColWidth := 222
    else
      Form1.StringGrid2.DefaultColWidth := 232;

        case op of
          0 : off := IntToBin(StrToInt(off),8);    //Base 2
          1 : ; //Base 10
          2 : off := IntToHex(StrToInt(off),1);//Base 16
          3 : off := '$'+IntToHex(StrToInt(off),1); //Append $
          4 : off := '0x'+IntToHex(StrToInt(off),1);//Append 0x
        end;

  form1.StringGrid2.Cells[0,(x-1)] := off;
  form1.StringGrid2.Cells[1,(x-1)] := IntToHex(by,2);
end;
procedure TCompareFilesThread.SProgBarNext;
begin
Form1.ProgressBar1.Position := Form1.ProgressBar1.Position + 1;
end;