并发

并发示例演示如何使用具有 ConcurrencyMode 枚举的 ServiceBehaviorAttribute,该枚举控制服务的实例是按顺序还是同时处理消息。 此示例基于入门指南中的示例,它实现 ICalculator 服务协定。 本示例定义从 ICalculatorConcurrency 中继承的新协定 ICalculator,该协定提供两个用于检查服务并发状态的附加操作。 通过更改并发设置,可以在运行客户端时观察到行为发生的变化。

在此示例中,客户端是一个控制台应用程序 (.exe),服务是由 Internet 信息服务 (IIS) 承载的。

注意

本主题的最后介绍了此示例的设置过程和生成说明。

有三种可用的并发模式:

  • Single:每个服务实例一次处理一个消息。 这是默认的并发模式。

  • Multiple:每个服务实例同时处理多个消息。 若要使用此并发模式,服务实现必须是线程安全的。

  • Reentrant:每个服务实例一次处理一个消息,但接受可重入调用。 仅当服务对外调用时才会接受这些调用。重入在 ConcurrencyMode.Reentrant 示例中进行了演示。

并发的使用与实例化模式有关。 在 PerCall 实例化过程中,与并发没有关系,因为每个消息都由一个新服务实例处理。 在 Single 实例化过程中,与 SingleMultiple 并发有关,具体取决于单个实例是依次还是同时处理消息。 在 PerSession 实例化过程中,可能与任何并发模式有关。

服务类使用 [ServiceBehavior(ConcurrencyMode=<setting>)] 属性来指定并发行为,如下面的代码示例所示。 通过更换注释掉的行,您可以体验 SingleMultiple 并发模式。 请记住,更改并发模式之后重新生成服务。

// Single allows a single message to be processed sequentially by each service instance.
//[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)]

// Multiple allows concurrent processing of multiple messages by a service instance.
// The service implementation should be thread-safe. This can be used to increase throughput.
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]

// Uses Thread.Sleep to vary the execution time of each operation.
public class CalculatorService : ICalculatorConcurrency
{
    int operationCount;

    public double Add(double n1, double n2)
    {
        operationCount++;
        System.Threading.Thread.Sleep(180);
        return n1 + n2;
    }

    public double Subtract(double n1, double n2)
    {
        operationCount++;
        System.Threading.Thread.Sleep(100);
        return n1 - n2;
    }

    public double Multiply(double n1, double n2)
    {
        operationCount++;
        System.Threading.Thread.Sleep(150);
        return n1 * n2;
    }

    public double Divide(double n1, double n2)
    {
        operationCount++;
        System.Threading.Thread.Sleep(120);
        return n1 / n2;
    }

    public string GetConcurrencyMode()
    {
        // Return the ConcurrencyMode of the service.
        ServiceHost host = (ServiceHost)OperationContext.Current.Host;
        ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
        return behavior.ConcurrencyMode.ToString();
    }

    public int GetOperationCount()
    {
        // Return the number of operations.
        return operationCount;
    }
}

默认情况下,此示例使用通过 Multiple 实例化的 Single 并发。 已经对客户端代码进行了修改,以便使用异步代理。 这允许客户端对服务进行多个调用,而不必在每个调用之间的等待响应。 您可以观察到服务并发模式的行为中的差异。

运行示例时,操作请求和响应将显示在客户端控制台窗口中。 显示运行服务所用的并发模式、调用每个操作,然后显示操作计数。 请注意,并发模式为 Multiple 时,返回结果的顺序与调用的顺序不同,因为服务同时处理多个消息。 通过将并发模式更改为 Single,可以按调用顺序返回结果,因为服务按顺序处理每个消息。 在客户端窗口中按 Enter 可以关闭客户端。

设置、生成和运行示例

  1. 请确保已执行 Windows Communication Foundation 示例的一次性安装过程

  2. 如果使用 Svcutil.exe 生成客户端代理,请确保包括 /async 选项。

  3. 若要生成 C# 或 Visual Basic .NET 版本的解决方案,请按照 Building the Windows Communication Foundation Samples中的说明进行操作。

  4. 要使用单机配置或跨计算机配置来运行示例,请按照运行 Windows Communication Foundation 示例中的说明进行操作。