AgrupamentoPooling

Este exemplo demonstra como estender Windows Communication Foundation (WCF) para dar suporte ao pooling de objetos.This sample demonstrates how to extend Windows Communication Foundation (WCF) to support object pooling. O exemplo demonstra como criar um atributo que seja sintaticamente e semanticamente semelhante à ObjectPoolingAttribute funcionalidade de atributo dos serviços corporativos.The sample demonstrates how to create an attribute that is syntactically and semantically similar to the ObjectPoolingAttribute attribute functionality of Enterprise Services. O pooling de objetos pode fornecer um aumento considerável para o desempenho de um aplicativo.Object pooling can provide a dramatic boost to an application's performance. No entanto, ele pode ter o efeito oposto se não for usado corretamente.However, it can have the opposite effect if it is not used properly. O pooling de objetos ajuda a reduzir a sobrecarga de recriação de objetos usados com frequência que exigem inicialização extensiva.Object pooling helps reduce the overhead of recreating frequently used objects that require extensive initialization. No entanto, se uma chamada para um método em um objeto em pool levar um tempo considerável para ser concluída, o pooling de objetos enfileirará solicitações adicionais assim que o tamanho máximo do pool for atingido.However, if a call to a method on a pooled object takes a considerable amount of time to complete, object pooling queues additional requests as soon as the maximum pool size is reached. Portanto, ele pode falhar ao fornecer algumas solicitações de criação de objeto lançando uma exceção de tempo limite.Thus it may fail to serve some object creation requests by throwing a timeout exception.

Observação

O procedimento de instalação e as instruções de Build para este exemplo estão localizados no final deste tópico.The setup procedure and build instructions for this sample are located at the end of this topic.

A primeira etapa na criação de uma extensão WCF é decidir o ponto de extensibilidade a ser usado.The first step in creating a WCF extension is to decide the extensibility point to use.

No WCF, o termo Dispatcher refere-se a um componente de tempo de execução responsável pela conversão de mensagens de entrada em invocações de método no serviço do usuário e pela conversão de valores de retorno desse método em uma mensagem de saída.In WCF the term dispatcher refers to a run-time component responsible for converting incoming messages into method invocations on the user’s service and for converting return values from that method to an outgoing message. Um serviço WCF cria um Dispatcher para cada ponto de extremidade.A WCF service creates a dispatcher for each endpoint. Um cliente WCF deve usar um Dispatcher se o contrato associado a esse cliente for um contrato duplex.A WCF client must use a dispatcher if the contract associated with that client is a duplex contract.

Os despachantes de canal e ponto de extremidade oferecem extensibilidade de canal e de todo o contrato expondo várias propriedades que controlam o comportamento do Dispatcher.The channel and endpoint dispatchers offer channel-and contract-wide extensibility by exposing various properties that control the behavior of the dispatcher. A DispatchRuntime propriedade também permite inspecionar, modificar ou personalizar o processo de expedição.The DispatchRuntime property also enables you to inspect, modify, or customize the dispatching process. Este exemplo se concentra na InstanceProvider propriedade que aponta para o objeto que fornece as instâncias da classe de serviço.This sample focuses on the InstanceProvider property that points to the object that provides the instances of the service class.

O IInstanceProviderThe IInstanceProvider

No WCF, o Dispatcher cria instâncias da classe de serviço usando um InstanceProvider , que implementa a IInstanceProvider interface.In WCF, the dispatcher creates instances of the service class using a InstanceProvider, which implements the IInstanceProvider interface. Essa interface tem três métodos:This interface has three methods:

O pool de objetosThe Object Pool

Uma IInstanceProvider implementação personalizada fornece a semântica de pool de objetos necessária para um serviço.A custom IInstanceProvider implementation provides the required object pooling semantics for a service. Portanto, esse exemplo tem um ObjectPoolingInstanceProvider tipo que fornece implementação personalizada do IInstanceProvider para pooling.Therefore, this sample has an ObjectPoolingInstanceProvider type that provides custom implementation of IInstanceProvider for pooling. Quando o Dispatcher chama o GetInstance(InstanceContext, Message) método, em vez de criar uma nova instância, a implementação personalizada procura um objeto existente em um pool na memória.When the Dispatcher calls the GetInstance(InstanceContext, Message) method, instead of creating a new instance, the custom implementation looks for an existing object in an in-memory pool. Se houver um disponível, ele será retornado.If one is available, it is returned. Caso contrário, um novo objeto será criado.Otherwise, a new object is created. A implementação do GetInstance é mostrada no código de exemplo a seguir.The implementation for GetInstance is shown in the following sample code.

object IInstanceProvider.GetInstance(InstanceContext instanceContext, Message message)  
{  
    object obj = null;  
  
    lock (poolLock)  
    {  
        if (pool.Count > 0)  
        {  
            obj = pool.Pop();  
        }  
        else  
        {  
            obj = CreateNewPoolObject();  
        }  
        activeObjectsCount++;  
    }  
  
    WritePoolMessage(ResourceHelper.GetString("MsgNewObject"));  
  
    idleTimer.Stop();  
  
    return obj;
}  

A ReleaseInstance implementação personalizada adiciona a instância liberada de volta ao pool e decrementa o ActiveObjectsCount valor.The custom ReleaseInstance implementation adds the released instance back to the pool and decrements the ActiveObjectsCount value. O Dispatcher pode chamar esses métodos de threads diferentes e, portanto, o acesso sincronizado aos membros de nível de classe na ObjectPoolingInstanceProvider classe é necessário.The Dispatcher can call these methods from different threads, and therefore synchronized access to the class level members in the ObjectPoolingInstanceProvider class is required.

void IInstanceProvider.ReleaseInstance(InstanceContext instanceContext, object instance)  
{  
    lock (poolLock)  
    {  
        pool.Push(instance);  
        activeObjectsCount--;  
  
        WritePoolMessage(  
        ResourceHelper.GetString("MsgObjectPooled"));  
  
        // When the service goes completely idle (no requests
        // are being processed), the idle timer is started  
        if (activeObjectsCount == 0)  
            idleTimer.Start();
    }  
}  

O ReleaseInstance método fornece um recurso de "inicialização de limpeza".The ReleaseInstance method provides a "clean up initialization" feature. Normalmente, o pool mantém um número mínimo de objetos durante o tempo de vida do pool.Normally the pool maintains a minimum number of objects for the lifetime of the pool. No entanto, pode haver períodos de uso excessivo que exigem a criação de objetos adicionais no pool para alcançar o limite máximo especificado na configuração.However, there can be periods of excessive usage that require creating additional objects in the pool to reach the maximum limit specified in the configuration. Eventualmente, quando o pool se torna menos ativo, esses objetos excedentes podem se tornar uma sobrecarga extra.Eventually, when the pool becomes less active, those surplus objects can become an extra overhead. Portanto, quando o activeObjectsCount chega a zero, um temporizador ocioso é iniciado que dispara e executa um ciclo de limpeza.Therefore, when the activeObjectsCount reaches zero, an idle timer is started that triggers and performs a clean-up cycle.

Adicionando o comportamentoAdding the Behavior

As extensões de camada de Dispatcher são conectadas usando os seguintes comportamentos:Dispatcher-layer extensions are hooked up using the following behaviors:

  • Comportamentos de serviço.Service Behaviors. Elas permitem a personalização de todo o tempo de execução do serviço.These allow for the customization of the entire service runtime.

  • Comportamentos de ponto de extremidade.Endpoint Behaviors. Eles permitem a personalização de pontos de extremidade de serviço, especificamente um Dispatcher de canal e de ponto final.These allow for the customization of service endpoints, specifically a Channel and Endpoint Dispatcher.

  • Comportamentos de contrato.Contract Behaviors. Eles permitem a personalização de ambas as ClientRuntime classes e do DispatchRuntime cliente e do serviço, respectivamente.These allow for the customization of both ClientRuntime and DispatchRuntime classes on the client and the service respectively.

Para a finalidade de uma extensão de pool de objetos, um comportamento de serviço deve ser criado.For the purpose of an object pooling extension a service behavior must be created. Os comportamentos de serviço são criados pela implementação da IServiceBehavior interface.Service behaviors are created by implementing the IServiceBehavior interface. Há várias maneiras de fazer com que o modelo de serviço reconheça os comportamentos personalizados:There are several ways to make the service model aware of the custom behaviors:

  • Usando um atributo personalizado.Using a custom attribute.

  • Adicionando imperativamente à coleção de comportamentos da descrição do serviço.Imperatively adding it to the service description’s behaviors collection.

  • Estendendo o arquivo de configuração.Extending the configuration file.

Este exemplo usa um atributo personalizado.This sample uses a custom attribute. Quando o ServiceHost é construído, ele examina os atributos usados na definição de tipo do serviço e adiciona os comportamentos disponíveis à coleção de comportamentos da descrição do serviço.When the ServiceHost is constructed it examines the attributes used in the service’s type definition and adds the available behaviors to the service description’s behaviors collection.

A interface IServiceBehavior tem três métodos Validate ,, AddBindingParameters e ApplyDispatchBehavior .The interface IServiceBehavior has three methods in it -- Validate, AddBindingParameters, and ApplyDispatchBehavior. O Validate método é usado para garantir que o comportamento possa ser aplicado ao serviço.The Validate method is used to ensure that the behavior can be applied to the service. Neste exemplo, a implementação garante que o serviço não esteja configurado com Single .In this sample, the implementation ensures that the service is not configured with Single. O AddBindingParameters método é usado para configurar as associações do serviço.The AddBindingParameters method is used to configure the service's bindings. Isso não é necessário neste cenário.It is not required in this scenario. O ApplyDispatchBehavior é usado para configurar os expedidores do serviço.The ApplyDispatchBehavior is used to configure the service's dispatchers. Esse método é chamado pelo WCF quando o ServiceHost está sendo inicializado.This method is called by WCF when the ServiceHost is being initialized. Os parâmetros a seguir são passados para este método:The following parameters are passed into this method:

  • Description: Esse argumento fornece a descrição do serviço para todo o serviço.Description: This argument provides the service description for the entire service. Isso pode ser usado para inspecionar dados de descrição sobre os pontos de extremidade, contratos, associações e outros dados do serviço.This can be used to inspect description data about the service’s endpoints, contracts, bindings, and other data.

  • ServiceHostBase: Esse argumento fornece o ServiceHostBase que está sendo inicializado no momento.ServiceHostBase: This argument provides the ServiceHostBase that is currently being initialized.

Na implementação personalizada IServiceBehavior , uma nova instância do ObjectPoolingInstanceProvider é instanciada e atribuída à InstanceProvider propriedade em cada uma DispatchRuntime das ServiceHostBase.In the custom IServiceBehavior implementation a new instance of ObjectPoolingInstanceProvider is instantiated and assigned to the InstanceProvider property in each DispatchRuntime in the ServiceHostBase.

void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)  
{  
    // Create an instance of the ObjectPoolInstanceProvider.  
    ObjectPoolingInstanceProvider instanceProvider = new  
           ObjectPoolingInstanceProvider(description.ServiceType,
                                                    minPoolSize);  
  
    // Forward the call if we created a ServiceThrottlingBehavior.  
    if (this.throttlingBehavior != null)  
    {  
        ((IServiceBehavior)this.throttlingBehavior).ApplyDispatchBehavior(description, serviceHostBase);  
    }  
  
    // In case there was already a ServiceThrottlingBehavior
    // (this.throttlingBehavior==null), it should have initialized
    // a single ServiceThrottle on all ChannelDispatchers.
    // As we loop through the ChannelDispatchers, we verify that
    // and modify the ServiceThrottle to guard MaxPoolSize.  
    ServiceThrottle throttle = null;  
  
    foreach (ChannelDispatcherBase cdb in
            serviceHostBase.ChannelDispatchers)  
    {  
        ChannelDispatcher cd = cdb as ChannelDispatcher;  
        if (cd != null)  
        {  
            // Make sure there is exactly one throttle used by all
            // endpoints. If there were others, we could not enforce
            // MaxPoolSize.  
            if ((this.throttlingBehavior == null) &&
                        (this.maxPoolSize != Int32.MaxValue))  
            {  
                throttle ??= cd.ServiceThrottle;
                if (cd.ServiceThrottle == null)  
                {  
                    throw new
InvalidOperationException(ResourceHelper.GetString("ExNullThrottle"));  
                }  
                if (throttle != cd.ServiceThrottle)  
                {  
                    throw new InvalidOperationException(ResourceHelper.GetString("ExDifferentThrottle"));  
                }  
             }  
  
             foreach (EndpointDispatcher ed in cd.Endpoints)  
             {  
                 // Assign it to DispatchBehavior in each endpoint.  
                 ed.DispatchRuntime.InstanceProvider =
                                      instanceProvider;  
             }  
         }  
     }  
  
     // Set the MaxConcurrentInstances to limit the number of items
     // that will ever be requested from the pool.  
     if ((throttle != null) && (throttle.MaxConcurrentInstances >
                                      this.maxPoolSize))  
     {  
         throttle.MaxConcurrentInstances = this.maxPoolSize;  
     }  
}  

Além de uma IServiceBehavior implementação, a ObjectPoolingAttribute classe tem vários membros para personalizar o pool de objetos usando os argumentos de atributo.In addition to an IServiceBehavior implementation the ObjectPoolingAttribute class has several members to customize the object pool using the attribute arguments. Esses membros incluem MaxPoolSize , MinPoolSize e CreationTimeout , para corresponder ao conjunto de recursos do pool de objetos fornecido pelo .net Enterprise Services.These members include MaxPoolSize, MinPoolSize, and CreationTimeout, to match the object pooling feature set provided by .NET Enterprise Services.

O comportamento do pool de objetos agora pode ser adicionado a um serviço do WCF anotando a implementação do serviço com o atributo personalizado recém-criado ObjectPooling .The object pooling behavior can now be added to a WCF service by annotating the service implementation with the newly created custom ObjectPooling attribute.

[ObjectPooling(MaxPoolSize=1024, MinPoolSize=10, CreationTimeout=30000)]
public class PoolService : IPoolService  
{  
  // …  
}  

Executando o exemploRunning the Sample

O exemplo demonstra os benefícios de desempenho que podem ser obtidos usando o pool de objetos em determinados cenários.The sample demonstrates the performance benefits that can be gained by using object pooling in certain scenarios.

O aplicativo de serviço implementa dois serviços – WorkService e ObjectPooledWorkService .The service application implements two services -- WorkService and ObjectPooledWorkService. Ambos os serviços compartilham a mesma implementação, ambos exigem uma inicialização cara e, em seguida, expõem um DoWork() método relativamente barato.Both services share the same implementation -- they both require expensive initialization and then expose a DoWork() method that is relatively cheap. A única diferença é que o ObjectPooledWorkService tem o pool de objetos configurado:The only difference is that the ObjectPooledWorkService has object pooling configured:

[ObjectPooling(MinPoolSize = 0, MaxPoolSize = 5)]  
public class ObjectPooledWorkService : IDoWork  
{  
    public ObjectPooledWorkService()  
    {  
        Thread.Sleep(5000);  
        ColorConsole.WriteLine(ConsoleColor.Blue, "ObjectPooledWorkService instance created.");  
    }  
  
    public void DoWork()  
    {  
        ColorConsole.WriteLine(ConsoleColor.Blue, "ObjectPooledWorkService.GetData() completed.");  
    }
}  

Quando você executa o cliente, ele se chama de WorkService 5 vezes.When you run the client, it times calling the WorkService 5 times. Em seguida, eles chamam o tempo de ObjectPooledWorkService 5 vezes.It then times calling the ObjectPooledWorkService 5 times. A diferença no tempo é exibida:The difference in time is then displayed:

Press <ENTER> to start the client.  
  
Calling WorkService:  
1 - DoWork() Done  
2 - DoWork() Done  
3 - DoWork() Done  
4 - DoWork() Done  
5 - DoWork() Done  
Calling WorkService took: 26722 ms.  
Calling ObjectPooledWorkService:  
1 - DoWork() Done  
2 - DoWork() Done  
3 - DoWork() Done  
4 - DoWork() Done  
5 - DoWork() Done  
Calling ObjectPooledWorkService took: 5323 ms.  
Press <ENTER> to exit.  

Observação

Na primeira vez em que o cliente é executado, ambos os serviços parecem levar aproximadamente na mesma quantidade de tempo.The first time the client is run both services appear to take about the same amount of time. Se você executar novamente o exemplo, poderá ver que o ObjectPooledWorkService retorna muito mais rápido porque já existe uma instância desse objeto no pool.If you re-run the sample, you can see that the ObjectPooledWorkService returns much quicker because an instance of that object already exists in the pool.

Para configurar, compilar, e executar o exemploTo set up, build, and run the sample

  1. Verifique se você executou o procedimento de configuração única para os exemplos de Windows Communication Foundation.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. Para compilar a solução, siga as instruções em criando os exemplos de Windows Communication Foundation.To build the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. Para executar o exemplo em uma configuração de computador único ou cruzado, siga as instruções em executando os exemplos de Windows Communication Foundation.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Observação

Se você usar Svcutil.exe para regenerar a configuração para este exemplo, certifique-se de modificar o nome do ponto de extremidade na configuração do cliente para corresponder ao código do cliente.If you use Svcutil.exe to regenerate the configuration for this sample, be sure to modify the endpoint name in the client configuration to match the client code.

Importante

Os exemplos podem já estar instalados no seu computador.The samples may already be installed on your machine. Verifique o seguinte diretório (padrão) antes de continuar.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Se esse diretório não existir, vá para Windows Communication Foundation (WCF) e exemplos de Windows Workflow Foundation (WF) para .NET Framework 4 para baixar todos os Windows Communication Foundation (WCF) e WFWF exemplos.If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WFWF samples. Este exemplo está localizado no seguinte diretório.This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WCF\Extensibility\Instancing\Pooling