Multithreading Delphi PPL TTask程序,带参数,ADOQuery

Multithreading Delphi PPL TTask程序,带参数,ADOQuery,multithreading,delphi,ado,Multithreading,Delphi,Ado,这是我上一篇文章的后续内容。我现在在过程中有几个ADO查询和一个ADO连接。所有这些都是动态创建和释放的 问题:如果我使用4个线程,我希望整个比较过程会快得多,但我的速度与没有线程时相同,只是现在要复杂得多。或者我在这里做了一些完全错误的事情 代码在这里,对不起,我知道它有点太多了,但是没有代码,我的问题没有意义,答案只能是猜测。MSSQL并没有包含在一次尝试中。最后我知道了,我只是想先检查一下这里是否有速度提升 按照要求粘贴整个过程。我还对其进行了修改,在循环外创建对象,在循环后创建自由对象

这是我上一篇文章的后续内容。我现在在过程中有几个ADO查询和一个ADO连接。所有这些都是动态创建和释放的

问题:如果我使用4个线程,我希望整个比较过程会快得多,但我的速度与没有线程时相同,只是现在要复杂得多。或者我在这里做了一些完全错误的事情

代码在这里,对不起,我知道它有点太多了,但是没有代码,我的问题没有意义,答案只能是猜测。MSSQL并没有包含在一次尝试中。最后我知道了,我只是想先检查一下这里是否有速度提升

按照要求粘贴整个过程。我还对其进行了修改,在循环外创建对象,在循环后创建自由对象

procedure TMain.SYNC(AProgressBar: TProgressBar; AData : array of RemoteDATA);
var i : integer;
    isFound : boolean;
    LStatus, LSU_Stueck, LHistLines , LPosLines, LSTLLines, LTXTLines, LKTXTLines : integer;
    ABQuery , HistQuery, PosQuery, STLQuery, TXTQuery, KTXTQuery : TADOQuery;
    MSSQL : TADOConnection;
begin
  MSSQL := TADOConnection.Create(nil);
  MSSQL.ConnectionString:='FILE NAME='+ExtractFilePath(Application.ExeName)+'\xlr_main.udl';
  MSSQL.Provider:='SQLOLEDB.1';
  MSSQL.KeepConnection:=true;
  MSSQL.LoginPrompt:=false;

  ABQuery := TADOQuery.Create(nil);
  ABQuery.Connection:=MSSQL;

  HistQuery := TADOQuery.Create(nil);
  HistQuery.Connection:=MSSQL;

  PosQuery := TADOQuery.Create(nil);
  PosQuery.Connection:=MSSQL;

  STLQuery := TADOQuery.Create(nil);
  STLQuery.Connection:=MSSQL;

  TXTQuery := TADOQuery.Create(nil);
  TXTQuery.Connection:=MSSQL;

  KTXTQuery := TADOQuery.Create(nil);
  KTXTQuery.Connection:=MSSQL;

  for i := Low(AData) to High(AData) do
    begin
      isFound:=false;
      LStatus:=0;
      LSU_Stueck:=0;
      LHistLines:=0;
      LPosLines:=0;
      LSTLLines:=0;
      LTXTLines:=0;
      LTXTLines:=0;


      ABQuery.SQL.Clear;
      ABQuery.SQL.Add('select AB,STATUS,SU_STUECK,DB_YEAR from BW_AUFTR_KOPF where AB='+inttostr(AData[i].AB)+' and DB_YEAR='+inttostr(AData[i].DB_YEAR));
      ABQuery.Open;

      if ABQuery.RecordCount <> 0 then
        begin
          isFound:=true;

          LStatus:=ABQuery.FieldByName('Status').AsInteger;
          LSU_Stueck:=ABQuery.FieldByName('SU_STUECK').AsInteger;
        end;


      HistQuery.SQL.Clear;
      HistQuery.SQL.Add('select COUNT(Datum) as HistLines from BW_AUFTR_HIST where AB='+inttostr(AData[i].AB)+' and DB_YEAR='+inttostr(AData[i].DB_YEAR));
      HistQuery.Open;

      LHistLines:=HistQuery.FieldByName('HistLines').AsInteger;

      PosQuery.SQL.Clear;
      PosQuery.SQL.Add('select COUNT(POS_NR) as PosLines from BW_AUFTR_POS where AB='+inttostr(AData[i].AB)+' and DB_YEAR='+inttostr(AData[i].DB_YEAR));
      PosQuery.Open;

      LPosLines:=PosQuery.FieldByName('PosLines').AsInteger;

      STLQuery.SQL.Clear;
      STLQuery.SQL.Add('select COUNT(POS_NR) as STLLines from BW_AUFTR_STL where AB='+inttostr(AData[i].AB)+' and DB_YEAR='+inttostr(AData[i].DB_YEAR));
      STLQuery.Open;

      LSTLLines:=STLQuery.FieldByName('STLLines').AsInteger;

      TXTQuery.SQL.Clear;
      TXTQuery.SQL.Add('select COUNT(POS_NR) as TXTLines from BW_AUFTR_TXT where AB='+inttostr(AData[i].AB)+' and DB_YEAR='+inttostr(AData[i].DB_YEAR));
      TXTQuery.Open;

      LTXTLines:=TXTQuery.FieldByName('TXTLines').AsInteger;

      KTXTQuery.SQL.Clear;
      KTXTQuery.SQL.Add('select COUNT(LFD_NR) as KTXTLines from BW_AUFTR_KTXT where AB='+inttostr(AData[i].AB)+' and DB_YEAR='+inttostr(AData[i].DB_YEAR));
      KTXTQuery.Open;

      LKTXTLines:=KTXTQuery.FieldByName('KTXTLines').AsInteger;


      if isFound = true then
        begin
            if (AData[i].STATUS <> LStatus) or (AData[i].SU_STUECK <> LSU_Stueck)
            or (AData[i].HISTLINES <> LHistLines) or (AData[i].POSLINES <> LPosLines) or (AData[i].STLLINES <> LSTLLines)
            or (AData[i].TXTLINES <> LTxtLines) or (AData[i].KTXTLINES <> LKTXTLines) then
              if (AData[i].STATUS < 100) and (AData[i].STATUS <> 98) then
                begin
                  setlength(CHANGED_ARRAY,length(CHANGED_ARRAY)+1);
                  CHANGED_ARRAY[High(CHANGED_ARRAY)].AB:=AData[i].AB;
                  CHANGED_ARRAY[High(CHANGED_ARRAY)].DB_YEAR:=AData[i].DB_YEAR;
                end;

            if (AData[i].STATUS = 98) or (AData[i].STATUS = 117) or (AData[i].STATUS = 900)
            or (AData[i].STATUS = 999) then
              begin
                setlength(DELETE_ARRAY,length(DELETE_ARRAY)+1);
                DELETE_ARRAY[High(DELETE_ARRAY)].AB:=AData[i].AB;
                DELETE_ARRAY[High(DELETE_ARRAY)].DB_YEAR:=AData[i].DB_YEAR;
              end;
        end
      else
        begin
          if (AData[i].STATUS <> 98) and (AData[i].STATUS <> 117) and (AData[i].STATUS <> 900)
          and (AData[i].STATUS <> 999) and (AData[i].STATUS <> 120) then
            begin
              setlength(NEW_ARRAY,length(NEW_ARRAY)+1);
              NEW_ARRAY[High(NEW_ARRAY)].AB:=AData[i].AB;
              NEW_ARRAY[High(NEW_ARRAY)].DB_YEAR:=AData[i].DB_YEAR;
            end;
        end;

      TThread.Queue(TThread.CurrentThread,
      procedure
      begin
        AProgressBar.Position:=i;
      end);

    end;

  ABQuery.Free;
  HistQuery.Free;
  PosQuery.Free;
  STLQuery.Free;
  TXTQuery.Free;
  KTXTQuery.Free;

  MSSQL.Free;
end;

这里的答案是,您需要分析代码和查询,以确定真正的瓶颈是什么。最有可能的情况是,大量的
SELECT COUNT…
查询没有合适的索引,SQL server被迫扫描表,导致磁盘受损,并造成了主要的串行瓶颈

不要使用no
ProcessMessages
循环,只需使用
TTask.WaitForAll(任务)
如果我使用4个线程,我希望整个比较过程会快得多。一个重要的教训是,你不会基于希望编程。如果您正在进行架构更改,您应该这样做,因为您知道这将比您现在所做的更好。猜测和检查只会浪费你大量的时间。你的瓶颈是什么?你为什么认为这会解决它?如果你不能回答这些问题,我就从这里开始。我可能猜内存争用是问题所在,但分析确实是这里的答案。神秘的
让任何人都很难说出您的问题可能是什么。也许你的瓶颈就在那里。谁知道呢?您正在每个循环迭代中创建并释放查询对象。。。这是非常低效和内存密集的(请记住,线程序列化对内存管理器的访问)。创建它们一次,完成后释放它们。您不需要执行
Length(AData)
次。此外,在查询中使用参数(而不是串联)将允许服务器缓存查询并提高性能。我接受这一点,因为我似乎确实需要使用探查器进行检查。数据库已建立索引。。。如你所见,我在AB和DB年后检查。。。这两个字段都被索引。。。计数通常小于10…@user1937012重要的不是返回计数的大小,而是您正在搜索以查找计数的表的大小。更新,我尝试了LockType:=ltReadOnly。砰的一声,现在它的速度非常快,有4个线程,我的工作时间是0.19秒,最后3次是难以置信的0.08秒。为了确保我看不到任何东西,我尝试了使用LockType ltReadOnly的原始单线程解决方案,它在0.47上做得更好,在那之后还有一些0.24,但远不及4个线程好。我查看了Microsofts网站上关于ADO锁类型的信息。如果我理解正确,ReadOnly表示没有锁定。我还看到线程速度有更大的变化,其中一些比其他更快。@user1937012那么你应该不接受这个答案,自己写一个
  if length(RAB_ARRAY) > 10 then
    begin
      Edit1.Text:='Items '+inttostr(length(RAB_ARRAY))+' 1/4 '+inttostr(length(RAB_ARRAY) div 4)+' LeftOver '+inttostr(length(RAB_ARRAY) mod 4);

      Part:=length(RAB_ARRAY) div 4;
      LeftOver:=length(RAB_ARRAY) mod 4;

      setlength(Tasks,4);

      Tasks[0] := TTask.Create(
        procedure
          begin
           SYNC(progressThread1,copy(RAB_ARRAY,0,Part))
          end);
      Tasks[1] := TTask.Create(
        procedure
          begin
            SYNC(progressThread2,copy(RAB_ARRAY,Part-1,Part))
          end);
      Tasks[2] := TTask.Create(
        procedure
          begin
            SYNC(progressThread3,copy(RAB_ARRAY,(2*Part)-2,Part))
          end);
      Tasks[3] := TTask.Create(
        procedure
          begin
            SYNC(progressThread4,copy(RAB_ARRAY,(3*Part)-3,Part+LeftOver))
          end);

      progressThread1.Max:=Part;
      progressThread2.Max:=Part;
      progressThread3.Max:=Part;
      progressThread4.Max:=Part+LeftOver;

      Tasks[0].Start;
      Tasks[1].Start;
      Tasks[2].Start;
      Tasks[3].Start;


      while true do
        begin
          if (Tasks[0].Status = TTaskStatus.Completed) and (Tasks[1].Status = TTaskStatus.Completed)
            and (Tasks[2].Status = TTaskStatus.Completed) and (Tasks[3].Status = TTaskStatus.Completed) then
              break;
          Application.ProcessMessages;
        end;