4

我有一个 WCF 服务,它依次调用其他几个 Web 服务。这些服务按优先顺序排序,但并行调用。每个服务都会以 true 或 false 进行响应,当所有响应都收到后,最喜欢的肯定会返回给客户端。

但是,在此期间的任何时候,最喜欢的服务都可能会做出积极的回应。此时继续查询其他服务没有意义,所以我希望取消执行并将结果返回给客户端。

我能做的就这么多:

// Use parallelOptions to store the cancellation token
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
Parallel.ForEach<IntegrationObj>(externalServices, po, x =>
{
    try
    {
        // Send requests
        SendExternalRequest(x);
        po.CancellationToken.ThrowIfCancellationRequested();
    }
    catch (OperationCanceledException e)
    {
        /// Don't throw an exception if the loop was cancelled
    }
    catch (Exception e)
    {
        LogError(e.Message);
    }
});
if (positiveResponses.Count > 0) {
    // Get the most preferred positive response and send it back to the client
    res = positiveResponses.Where(
        x => x.ID == PreferredServiceID)
        .FirstOrDefault();
}
return res;

上面的代码是我的代码的一个非常简化的版本,但本质上它会检查每个响应以查看它是否是当前最受欢迎的服务。如果是这样,它会取消循环。

但是...以这种方式取消循环将等待已经调用的任何服务在终止循环之前完成。任何服务都有可能超时,这当然被视为否定。如果只是其中一个超时,它会在我的响应时间上增加 10 秒。

我想做的是以下之一:

  1. 将首选服务返回给客户端,然后继续处理来自已经启动的服务的响应(这纯粹是为了记录目的,以便我知道这些服务的正/负率)。
  2. 立即取消循环并忘记剩余的响应。理想情况下,我不想这样做,因为这意味着将不会记录本应积极响应的服务,这将影响他们的偏好评级。

所以我的问题是:

我想要实现的目标可能吗?我意识到 parallel.foreach 可能不是这项工作的最佳工具,或者我可能无法在响应客户端后记录响应。最重要的要求是当“赢家”已经被选中时,客户端无需等待服务响应即可收到快速响应。

4

1 回答 1

1

当前设置的方式是您的所有服务都并行启动,但您的检查仅编程为在所有服务完成后发生。
如果你想坚持你的 foreach 方法,你可以在 foreach 中编写你的 if 条件,这样如果服务首先完成,它将直接执行对积极响应的检查,你可以做出相应的反应(返回值/杀死其他人)。
请注意,这种方法有更多的线程不安全性,您必须小心处理(您从您的一个服务可能试图写入的列表中读取)。也有可能 2 个服务同时完成,因此您的 if 语句会触发两次。

foreach 方法的另一种方法是为每个服务创建一个线程,将所有线程放在一个列表中,并在启动所有线程后立即启动一个 while 循环以继续检查(当然是休眠)完成的服务。这样,您可以在其他线程仍在运行时通过中断 while 循环返回值。

于 2012-04-26T13:41:28.253 回答