使用并行编程库在计算值列表中查找最大值
Find the Maximum in a List of calculated values using the Parallel Programming Library
我有一个值列表。我想找到最大值。这是一项常见的任务。一个简单的版本可能是:
iBest := -1;
iMax := -1e20;
for i := 0 to List.Count - 1 do
begin
if List[i].Value > iMax then
begin
iBest := i;
iMax := List[i].Value;
end;
end;
在我的例子中,.Value
getter 是性能瓶颈,因为它调用耗时的计算(~100 毫秒),returns 最终值。
如何使用并行编程库实现并行?
如果该值是一个计算值并且您可以负担得起缓存,一个简单的解决方案可能如下所示:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, Threading, DateUtils, Math, Generics.Collections, StrUtils;
type
TFoo = class
private
FCachedValue : double;
function GetValue : double;
public
property CalculateValue : double read GetValue;
property CachedValue : double read FCachedValue;
end;
TFooList = class(TObjectList<TFoo>)
public
procedure CalculateValues;
function GetMaxValue(var BestIndex : integer) : double;
end;
function TFoo.GetValue : double;
begin
sleep(10); // simulate taking some time... make up a value
FCachedValue := DateUtils.MilliSecondOfTheSecond(now);
result := FCachedValue;
end;
procedure TFooList.CalculateValues;
begin
TParallel.For(0, Count - 1,
procedure (j:integer)
begin
self[j].CalculateValue;
end);
end;
function TFooList.GetMaxValue(var BestIndex : Integer) : double;
var
i, iBest : integer;
maxval : double;
begin
CalculateValues;
iBest := 0;
maxval := self[0].CachedValue;
for i := 0 to self.Count - 1 do
begin
if self[i].CachedValue > maxval then
begin
iBest := i;
maxval := self[i].CachedValue;
end;
end;
BestIndex := iBest;
result := maxval;
end;
var
LFooList : TFooList;
i, iBest : integer;
maxval : double;
begin
LFooList := TFooList.Create(true);
try
for i := 0 to 9999 do LFooList.Add(TFoo.Create);
maxval := LFooList.GetMaxValue(iBest);
WriteLn(Format('Max value index %d', [iBest]));
WriteLn(Format('Max value %.6f', [maxval]));
finally
LFooList.Free;
end;
ReadLn;
end.
这样,您的对象会保留上次计算值的缓存,您可以随时刷新,但也可以快速访问。并行化列表的完整计算比并行化 min/max 搜索要容易一些,如果瓶颈是计算,那么将增加的复杂性限制在单独的操作(你知道开销的地方)是有意义的是值得的)。
我有一个值列表。我想找到最大值。这是一项常见的任务。一个简单的版本可能是:
iBest := -1;
iMax := -1e20;
for i := 0 to List.Count - 1 do
begin
if List[i].Value > iMax then
begin
iBest := i;
iMax := List[i].Value;
end;
end;
在我的例子中,.Value
getter 是性能瓶颈,因为它调用耗时的计算(~100 毫秒),returns 最终值。
如何使用并行编程库实现并行?
如果该值是一个计算值并且您可以负担得起缓存,一个简单的解决方案可能如下所示:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, Threading, DateUtils, Math, Generics.Collections, StrUtils;
type
TFoo = class
private
FCachedValue : double;
function GetValue : double;
public
property CalculateValue : double read GetValue;
property CachedValue : double read FCachedValue;
end;
TFooList = class(TObjectList<TFoo>)
public
procedure CalculateValues;
function GetMaxValue(var BestIndex : integer) : double;
end;
function TFoo.GetValue : double;
begin
sleep(10); // simulate taking some time... make up a value
FCachedValue := DateUtils.MilliSecondOfTheSecond(now);
result := FCachedValue;
end;
procedure TFooList.CalculateValues;
begin
TParallel.For(0, Count - 1,
procedure (j:integer)
begin
self[j].CalculateValue;
end);
end;
function TFooList.GetMaxValue(var BestIndex : Integer) : double;
var
i, iBest : integer;
maxval : double;
begin
CalculateValues;
iBest := 0;
maxval := self[0].CachedValue;
for i := 0 to self.Count - 1 do
begin
if self[i].CachedValue > maxval then
begin
iBest := i;
maxval := self[i].CachedValue;
end;
end;
BestIndex := iBest;
result := maxval;
end;
var
LFooList : TFooList;
i, iBest : integer;
maxval : double;
begin
LFooList := TFooList.Create(true);
try
for i := 0 to 9999 do LFooList.Add(TFoo.Create);
maxval := LFooList.GetMaxValue(iBest);
WriteLn(Format('Max value index %d', [iBest]));
WriteLn(Format('Max value %.6f', [maxval]));
finally
LFooList.Free;
end;
ReadLn;
end.
这样,您的对象会保留上次计算值的缓存,您可以随时刷新,但也可以快速访问。并行化列表的完整计算比并行化 min/max 搜索要容易一些,如果瓶颈是计算,那么将增加的复杂性限制在单独的操作(你知道开销的地方)是有意义的是值得的)。