4

我正在学习如何在 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 的新手,我不知道该怎么做,请帮助我:)

4

2 回答 2

0

取消令牌只是其中的一半。如果需要它返回一个值,则需要使用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;

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

于 2014-03-19T00:34:17.323 回答
0

You need to use a cancellation token:

var
  cancelToken: IOmniCancellationToken;

You obtain the cancellation token by calling CreateOmniCancellationToken from the OtlSync unit.

cancelToken := CreateOmniCancellationToken;

You then supply the token to the parallel loop:

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

And you signal the cancellation token by calling its Signal method.

cancelToken.Signal;

From outside the parallel loop you can use

cancelToken.IsSignaled

to detect that you cancelled. Or you can capture a boolean variable from the surrounding scope and pass the information through that variable.

The example here gives an illustration.

于 2014-03-18T23:20:56.877 回答