Delphi TParallel.For - 无法捕获符号

Delphi TParallel.For - Cannot Capture Symbol

我只知道 Delphi XE7 有 Parallel.For 这很酷。所以我尝试转换一小段代码,比如:

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 更新 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 未使用,正如编译器观察到的那样,应将其删除。并不是说它有什么不同。

我无法解释为什么您无法编译此代码。您使用的编译器与我不同,或者代码与我不同。


更新

事实上,从您的问题更新来看,您没有 post编辑无法编译的代码。

这里的重要教训是永远不要 post 假代码。始终 post 真实代码,尽可能完整的代码,尽可能少。

至于你的真实代码,你刚刚 posted,看起来像这样:

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 参数,编译器不知道变量的声明位置。见 Anonymous Methods Variable Binding:

A key feature of anonymous methods is that they may reference variables that are visible to them where they were defined.

您需要按照以下方式使用:

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 参数。好吧,我们可以在循环开始之前平均分配,但我觉得这在语义上很奇怪。