德尔福TParallel.For语言 - 不能捕获符号



我只知道从Delphi XE7有并行。这很酷。所以我尝试转换一小段代码,例如:

procedure TestParallel;
var
  i, j, u, v: integer;
  map: array of array of integer;
begin
  SetLength(map, 101, 101);
  u := 100; v := 100;
  for i := 0 to u do
  begin
    for j := 0 to v do
    begin
      if (map[i][j] <> 0) then
      begin
        map[i][j] := 1;
      end;
    end;
  end;
end;

:

procedure TestParallel;
var
  i, u, v: integer;
  map: array of array of integer;
begin
  SetLength(map, 101, 101);
  u := 100; v := 100;
  TParallel.&For(0, u, procedure(i: integer)
  var
    j: integer;
  begin
    for j := 0 to v do
    begin
      if (map[i][j] <> 0) then
      begin
        map[i][j] := 1;
      end;
    end;
  end);
end;

更新

是的,上面的代码可以编译,而下面的代码不能(如果map数组作为var参数传递)

type
   data = array of array of integer;
procedure TestParallel(var map: data);
var
  i, u, v: integer;
begin
  SetLength(map, 101, 101);
  u := 100; v := 100;
  TParallel.&For(0, u, procedure(i: integer)
  var
    j: integer;
  begin
    for j := 0 to v do
    begin
      if (map[i][j] <> 0) then
      begin
        map[i][j] := 1;
      end;
    end;
  end);
end;

不幸的是,编译器说:

[dcc64 Error] Project2.dpr(70): E2555 Cannot capture symbol 'map'

那么,如何使这个工作尽可能简单呢?

此代码与问题中的代码相同,在Delphi XE7 update 1上同时在dcc32和dcc64上编译。

program Project1;
uses
  System.Threading;
procedure TestParallel;
var
  i, u, v: integer;
  map: array of array of integer;
begin
  SetLength(map, 101, 101);
  u := 100; v := 100;
  TParallel.&For(0, u, procedure(i: integer)
  var
    j: integer;
  begin
    for j := 0 to v do
    begin
      if (map[i][j] <> 0) then
      begin
        map[i][j] := 1;
      end;
    end;
  end);
end;
begin
end.

编译器观察到,TestParallel中的局部变量i是未使用的,应该删除。这没什么区别。

我无法解释为什么您无法编译此代码。要么你用的编译器和我不一样,要么你的代码和我不一样。


事实上,从你的问题更新,事实证明,你没有张贴不编译的代码。

这里最大的教训是,永远不要发布虚假代码。如果可能的话,一定要发布真实的代码,完整的代码,尽可能少。

对于您刚刚发布的实际代码,它看起来像这样:

procedure TestParallel(var map: data);
var
  i, u, v: integer;
begin
  SetLength(map, 101, 101);
  u := 100; v := 100;
  TParallel.&For(0, u, procedure(i: integer)
  var
    j: integer;
  begin
    for j := 0 to v do
    begin
      if (map[i][j] <> 0) then
      begin
        map[i][j] := 1;
      end;
    end;
  end);
end;

编译失败,因为无法捕获var参数。编译器必须能够在编译声明变量的函数时看到捕获是必要的。对于var参数,编译器不知道变量在哪里声明。参见匿名方法变量绑定:

匿名方法的一个关键特性是它们可以引用在定义它们的地方对它们可见的变量。

您需要使用以下内容:

procedure TestParallel(var map: TArray<TArray<Integer>>);
var
  LocalMap: TArray<TArray<Integer>>;
  u, v: integer;
begin
  SetLength(LocalMap, 101, 101);
  TParallel.&For(0, high(LocalMap), procedure(i: integer)
  var
    j: integer;
  begin
    for j := 0 to high(LocalMap[i]) do
    begin
      if (LocalMap[i][j] <> 0) then
      begin
        LocalMap[i][j] := 1;
      end;
    end;
  end);
  map := LocalMap;
end;

声明一个可以捕获的局部变量。然后我们可以在循环完成后赋值给var参数。好吧,我们可以在循环开始前相等地赋值,但我觉得这在语义上很奇怪。

最新更新