1

以下面的代码为例:

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使用后释放项目对于最小化内存使用很重要。

4

3 回答 3

2

简单的回答:你不会。

更复杂的答案:您在并行化操作中要做的最后一件事是修改共享状态,例如这个删除调用。因为不能保证每个单独的任务都会“按顺序”完成——事实上,它们很可能至少不会完成一次,随着你添加到总工作量中的任务越多,这种概率很快就会接近 100%——试图做这样的事情是在玩火。

您可以随时销毁项目并对其进行序列化,也可以并行执行,更快完成并销毁整个列表。但我认为没有任何办法可以同时兼顾。

于 2014-11-25T22:35:00.747 回答
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;

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

于 2014-11-25T23:28:23.927 回答
1

我不会尝试展示如何执行您最初要求的操作,因为这是一个不会提高性能的坏主意。甚至不假设您在提议的并行实现中处理许多不同的数据竞争。

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

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

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

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

于 2014-11-26T07:24:52.027 回答