【问题标题】:How to terminate a parallel.foreach from OTL in Delphi xe2如何从Delphi xe2中的OTL终止parallel.foreach
【发布时间】:2014-03-18 23:09:20
【问题描述】:

我正在学习如何在 Delphi XE2 中使用 OmniThreadLibrary,我想知道是否有人可以告诉我如何取消 parallel.foreach。

我读到我应该使用取消令牌,但我找不到某种关于如何使用它的示例。

这是函数内部的原始 for 循环。

function SomeFunction() : string;
begin

  for value :=  0 to length(listOfThings)-1 do
  begin

    Chain := Function1( listOfThings[value] );

    if Evaluate( Chain , Solution) then
      Parameters[value] := Solution
    else
    begin
      Result := 'ERROR';
      exit;
    end;
  end;
end;

这就是我使用 Parallel.ForEach 的方式

function SomeFunction() : string;
begin

  Parallel.ForEach(0, length(listOfThings)-1 ).Execute(

    procedure (const value: integer)
        var Chain : string;
        begin
          Chain := Function1(listOfThings[value]);

        if Evaluate(Chain , Solution) then
          Parameters[value] := Solution
        else
          begin
            Result := 'ERROR';    //Here is where it won't work
            exit;  
          end;
        end
  );
end;

在 Parallel.ForEach 内部我不能做 Result := 'ERROR' 因为它没有在程序内部捕获,所以我想如果我可以取消 Parallel.ForEach 并报告取消,那么我可以在外部分配 Result := 'ERROR' .

但我是 OmniThreadLibrary 的新手,我不知道该怎么做,请帮助我:)

【问题讨论】:

    标签: delphi foreach parallel-processing omnithreadlibrary


    【解决方案1】:

    您需要使用取消令牌:

    var
      cancelToken: IOmniCancellationToken;
    

    您可以通过从OtlSync 单元调用CreateOmniCancellationToken 来获取取消令牌。

    cancelToken := CreateOmniCancellationToken;
    

    然后将令牌提供给并行循环:

    Parallel.ForEach(...)
        .CancelWith(cancelToken)
        .Execute(...);
    

    然后您通过调用其Signal 方法来发出取消令牌的信号。

    cancelToken.Signal;
    

    您可以在并行循环之外使用

    cancelToken.IsSignaled
    

    检测您已取消。或者您可以从周围的范围中捕获一个布尔变量,并通过该变量传递信息。

    例子here给出了一个说明。

    【讨论】:

    • 对此只是一个警告。如果你有一个 OnStop 事件,这将在正常完成和取消时调用。
    • 这将简单地终止并行迭代;他正在寻找一种方法来报告错误情况。
    • @Mason 他已经在问题中描述了如何做到这一点。问题是如何终止 for each 循环。
    【解决方案2】:

    取消令牌只有一半。如果需要它返回值,则需要使用Aggregate,因为序列中可以有任意数量的元素,但只有一个返回值,因此需要折叠(聚合)任意数量的将值返回为一个最终值。所以你想要这样的东西:

    function SomeFunction() : string;
    var
      cancelToken: IOmniCancellationToken;
      error: TOmniValue;
    begin
      cancelToken := CreateOmniCancellationToken;
      error := Parallel.ForEach(0, length(listOfThings)-1 ).
        CancelWith(cancelToken).
        Aggregate('',
          procedure(var aggregate: TOmniValue; const value: TOmniValue)
          var Chain : string;
          begin
            Chain := Function1(listOfThings[value]);
    
          if Evaluate(Chain , Solution) then
            Parameters[value] := Solution
          else
            begin
              aggregate := 'ERROR';
              cancelToken.signal;
            end;
          end).
      Execute(
        procedure(const value: TOmniValue; var result: TOmniValue)
        begin
          if value <> '' then
            result := value;
        end);
    
      if error <> '' then
        //something went wrong
    end;
    

    这可能并不完美,但它应该能让你走上正轨。

    【讨论】:

    • 聚合在这里居于首位。从包含范围捕获变量或使用令牌本身更容易:IsSignaled。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多