6

我的代码运行 4 个函数来将信息(使用调用)填充到一个类中,例如:

class Person
{
    int Age;
    string name;
    long ID;
    bool isVegeterian

    public static Person GetPerson(int LocalID)
    {
        Person person;
        Parallel.Invoke(() => {GetAgeFromWebServiceX(person)}, 
                        () => {GetNameFromWebServiceY(person)},
                        () => {GetIDFromWebServiceZ(person)},
                        () => 
                        {
                           // connect to my database and get information if vegeterian (using LocalID)
                           ....
                           if (!person.isVegetrian)
                               return null
                           ....
                        });
     }
}

我的问题是:如果他不是素食者,我不能返回 null,但我希望能够停止所有线程,停止处理并返回 null。如何实现?

4

3 回答 3

8

Parallel.Invoke要尽早退出,您必须做三件事:

  1. 安排检测您是否要提前退出的操作作为第一个操作。然后它会尽快安排(可能是第一次,但不能保证),所以你会更快地知道你是否想退出。
  2. AggregateException当您检测到错误并按照 Jon 的回答指示捕获错误时抛出异常。
  3. 使用取消令牌。IsCancellationRequested但是,这只有在您有机会检查他们的财产时才有意义。

您的代码将如下所示:

var cts = new CancellationTokenSource();
try
{
    Parallel.Invoke(
        new ParallelOptions { CancellationToken = cts.Token },
        () =>
        {
            if (!person.IsVegetarian)
            {
                cts.Cancel();
                throw new PersonIsNotVegetarianException();
            }
        },
        () => { GetAgeFromWebServiceX(person, cts.Token) }, 
        () => { GetNameFromWebServiceY(person, cts.Token) },
        () => { GetIDFromWebServiceZ(person, cts.Token) }
    );
}
catch (AggregateException e)
{
    var cause = e.InnerExceptions[0];
    // Check if cause is a PersonIsNotVegetarianException.
}

但是,正如我所说,取消令牌只有在您可以检查它们时才有意义。所以内部应该有机会GetAgeFromWebServiceX检查取消令牌并提前退出,否则将令牌传递给这些方法没有意义。

于 2010-09-16T08:17:27.433 回答
4

好吧,您可以从您的操作中抛出一个异常,捕获(即AggregateExceptionGetPerson周围放置一个 try/catch 块Parallel.Invoke),检查它是否是正确的异常类型,然后返回 null。

除了停止所有线程之外,这满足了一切。我认为除非您开始使用取消令牌,否则您不太可能轻易停止已经运行的任务。您可以通过保留一个值来停止执行进一步boolean的任务,以指示到目前为止是否有任何任务失败,并让每个任务在开始之前检查...这有点难看,但它会起作用。

我怀疑使用“完整”任务而不是Parallel.Invoke会使所有这些更加优雅。

于 2010-09-16T06:37:35.130 回答
2

当然你需要Person先从数据库中加载你的?因为它是您的代码调用带有 null 的 Web 服务。

如果您的逻辑确实是顺序的,请按顺序执行,并且仅并行执行有意义的操作。

于 2010-10-01T02:39:04.663 回答