如何在delphi中并行编码for-down-to循环,在列表上激活,在你去的时候删除项目?

时间:2014-11-25 22:27:43

标签: delphi for-loop parallel-processing delphi-xe2 omnithreadlibrary

以下面的代码为例:

for i := (myStringList.Count - 1) DownTo 0 do begin
  dataList := SplitString(myStringList[i], #9);
  x := StrToFloat(dataList[0]);
  y := StrToFloat(dataList[1]);
  z := StrToFloat(dataList[2]);
  //Do something with these variables
  myOutputRecordArray[i] := {SomeFunctionOf}(x,y,z)
  //Free Used List Item 
  myStringList.Delete(i);
end;
//Free Memory
myStringList.Free;

如何使用OmniThreadLibrary进行并行化?可能吗?还是需要重组?

我在每次迭代时调用myStringList.Delete(i);,因为StringList很大,并且在每次迭代使用后释放项目对于最小化内存使用非常重要。

3 个答案:

答案 0 :(得分:2)

简单回答:你不会。

更多参与答案:在并行操作中,您要做的最后一件事是修改共享状态,例如此删除调用。由于不能保证每个单独的任务都能完成"顺序" - 实际上很可能他们至少赢了一次,这个概率接近了100%非常快,您添加到总工作量的任务越多 - 尝试做类似的事情就是玩火。

您可以随意销毁这些项目并进行序列化,也可以并行执行,完成更快,并销毁整个列表。但我认为没有任何办法可以双管齐下。

答案 1 :(得分:2)

你可以作弊。将字符串值设置为空字符串将释放大部分内存并且将是线程安全的。在处理结束时,您可以清除列表。

Parallel.ForEach(0, myStringList.Count - 1).Execute(
  procedure (const index: integer)
  var
    dataList: TStringDynArray;
    x, y, z: Single;
  begin
    dataList := SplitString(myStringList[index], #9);
    x := StrToFloat(dataList[0]);
    y := StrToFloat(dataList[1]);
    z := StrToFloat(dataList[2]);
    //Do something with these variables
    myOutputRecordArray[index] := {SomeFunctionOf}(x,y,z);
    //Free Used List Item
    myStringList[index] := '';
  end);
myStringList.Clear;

这段代码是安全的,因为我们永远不会从多个线程写入共享对象。您需要确保您使用的所有通常都是本地的变量都在线程块中声明。

答案 2 :(得分:1)

我不会试图展示如何做你最初提出的问题,因为这不会导致性能提升。甚至没有假设您在提议的并行实现中处理了许多不同的数据争用。

这里的瓶颈是磁盘I / O.将整个文件读入内存,然后处理内容是导致内存问题的设计选择。解决此问题的正确方法是使用管道。

管道的第1步将磁盘上的文件作为输入。这里的代码读取文件的块,然后将这些块分成行。这些行是此步骤的输出。整个文件一次永远不会在内存中。您必须调整您阅读的块的大小。

步骤2将步骤1产生的字符串作为输入。第2步消耗这些字符串并生成向量。这些向量将添加到矢量列表中。

第2步将比第1步更快,因为I / 0非常昂贵。因此,尝试使用并行算法优化任一步骤都无法获得任何好处。即使在单处理器机器上,这种流水线实现也可能比非流水线更快。