Delphi XE7如何处理并行任务中的多线程

Jim*_*ean 0 delphi parallel-processing multithreading task

我是并行编程的新手,我试图找出为什么偶尔会得到一个EmonitorLockException:当我增加要运行的并行任务的数量时,不拥有对象锁.是这样的情况,线程变得纠结我运行的任务越多.或者我的代码不正确?

{$APPTYPE CONSOLE}

uses
System.SysUtils, System.Threading, System.Classes, System.SyncObjs, System.StrUtils;

const

WorkerCount = 10000; // this is the number of tasks to run in parallel    note:when this number is increased by repeated factors of 10
                  // it takes longer to produce the result and sometimes the program crashes
                  // with an EmonitorLockException:Object lock not owned . Is it that my program is not written correctly or efficiently to run
                  // a large number of parallel taks and the Threads become entagled.
                  // Eventually I would like to optimeize the program to find the optimal number of tasks to run in parallel so as to find the result in the shortest time.
                  // This becomes important when the word sequence is increased to six or more letters.

sequencetofind='help'; // letter sequence to find randomly
sequencelengthplus1=5;  // the ength of the letter sequence plus 1 extra   letter for a check to see if it is working


var
  Ticks: Cardinal;
  i,k,m: Integer;
  sequencenum: Integer;
  alphabetarray:array[1..26] of string;
  v:char;
  copyarray,letters:array[1..sequencelengthplus1] of string;
  tasks: array of ITask;
  LTask: ITask;
  Event1:TEvent;
  sequencesection:TCriticalSection;

  function findsequencex(index: Integer): TProc;    
  begin
    Result := procedure
              var
                counter,m:integer;
                r:integer;
                z:string;
                lettersx:array[1..sequencelengthplus1] of string;
              begin
                for m:=1 to sequencelengthplus1-1 do
                  lettersx[m]:=letters[m];
                randomize;
                counter:=1;
                repeat
                  r:=random(26)+1;
                  z:=alphabetarray[r];              //randomly find letters until matched    with the sequence

                  if z=letters[counter] then 
                  begin
                    copyarray[counter]:=z;
                    counter:=counter+1;      // increase counter when successfully found a match
                  end
                  else 
                    counter:=1;       // if match fails start again and look for the first letter

                  if (counter=sequencelengthplus1) then 
                  begin      // if all letters found in correct order find one more letter as a check

                    sequencesection.Acquire;                   //critical                  section start
                    r:=random(26)+1;
                    z:=alphabetarray[r];

                    TInterlocked.CompareExchange(sequencenum,r,0);
                    copyarray[sequencelengthplus1]:=z;
                    Event1.SetEvent;                                 // set in motion the process to stop all other tasks
                    sequencesection.release;                    // critical section end
                  end;
                until (Event1.WaitFor(0)=wrSignaled);      // check to see if all letters of the sequence has been found
              end;
  end;



  procedure Parallel2;
  var
    i,sequencevalue,j: Integer;
  begin
    Event1:=TEvent.Create(nil,true,false,'noname');    // sequence checker
    Event1.resetevent;
    sequencenum := 0;
    Ticks := TThread.GetTickCount;
    SetLength(Tasks, WorkerCount);             // number of parallel tasks to undertake
    for i := 0 to WorkerCount-1 do
      Tasks[i]:=TTask.Run(findsequencex(i));
    TTask.WaitForAny(Tasks);             // wait for the first one to   successfully finish
    TThread.Synchronize(nil,
               procedure
               begin
                 for LTask in Tasks do
                   LTask.Cancel;                                  // kill   the remaining tasks
                 TInterlocked.Add (sequencevalue, sequencenum);   // note   the random letter check
               end);
    Ticks := TThread.GetTickCount - Ticks;
    writeln('Parallel time ' + Ticks.ToString + ' ms, last random alphabet sequence number: ' + sequencenum.ToString+' random letter is = '+alphabetarray[sequencevalue]);
  end;
begin
  sequencesection:=TCriticalSection.Create;
  for m:=1 to  (sequencelengthplus1-1) do
  begin
    letters[m]:=copy(sequencetofind,m,1);
    writeln(letters[m]);
  end;
  i:=0;
  for v:='a' to 'z' do
  begin
    i:=i+1;
    alphabetarray[i]:=v;
  end;
  try
    begin
      Parallel2;    // call the parrallel procedure
      writeln('finished');
     for m:=1 to sequencelengthplus1 do
       writeln(copyarray[m]);
     if (Event1.WaitFor(0)=wrSignaled) then 
     begin
       writeln('event signaled');
       if (sequencenum=0) then writeln('sequence is null');
     end;
     Event1.Free;
     sequencesection.free;
   end;
  except
    on E: Exception do
    Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
 end.
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 9

您可以访问大量共享的全局变量而无需任何同步.例如:

  if z = letters[counter] then
  begin
    copyarray[counter] := z;
    counter := counter + 1;
    // increase counter when successfully found a match
  end
Run Code Online (Sandbox Code Playgroud)

copyarray是一个在所有任务之间共享的全局.仅此数据竞争可能会导致您看到的错误.还有其他类似的比赛.我相信还有很多问题.整个代码无法挽救.你需要扔掉它然后重新开始.

以下是一些提示:

  1. 选择一个更简单的任务来开始学习并行编程.
  2. 找一本关于这个主题的好书或教程.从小处着手,解决您的实际问题.
  3. 停止使用全局变量.与全局变量共享数据只会导致痛苦.分享是你的敌人.保持最低限度.
  4. 如果需要以显式方式共享数据,而不是使用全局变量.并确保同步访问共享数据.
  5. 不要Randomize从你的线程内部调用.这不是线程安全的.在启动时调用一次.
  6. Random不是线程安全的.找到一个线程安全的PRNG,或同步调用Random.前一种选择是首选.
  7. 不要TThread.Synchronize从主线程调用.
  8. 以标准方式管理生命.创建对象时,请使用tryfinally保护其生命周期.不要在一个函数中创建对象并在其他函数中销毁它们.
  9. 格式化代码以使其可读.如果您无法阅读代码,您将如何理解它?
  10. 有了最大的尊重,很明显你还没有掌握串行编程.在转向并行编程之前,您的目标应该是精通串行编程.并行编程至少要难一个数量级.
  11. 考虑到这一点,尝试以串行形式编写一个好的,干净的程序版本.然后考虑如何将其转换为并行版本.

  • 你需要扔掉所有的代码.这根本没有意义.你无法从中获得任何有用的东西. (3认同)
  • @JimmyDean并行编程在Delphi中并不新鲜.有一些新功能可以使某些问题的代码更加简洁; 但基本上,你可以创建并行编程,因为你可以创建一个线程.无论您使用哪种库/语言功能,您必须理解的概念问题都是相同的.您需要了解以下内容:封装,如何管理复杂性和关注点分离***之前***投入并行编程特有的复杂性.如:并发,竞争条件,死锁,同步,事件 (3认同)