PoolingPooling

Dieses Beispiel veranschaulicht das Erweitern von Windows Communication Foundation (WCF), um Objektpooling zu unterstützen.This sample demonstrates how to extend Windows Communication Foundation (WCF) to support object pooling. Das Beispiel veranschaulicht die Erstellung eines Attributs, das syntaktisch und semantisch ähnlich zur ObjectPoolingAttribute-Attributfunktionalität von Enterprise Services ist.The sample demonstrates how to create an attribute that is syntactically and semantically similar to the ObjectPoolingAttribute attribute functionality of Enterprise Services. Durch Objektpooling lässt sich die Leistung einer Anwendung u. U. drastisch steigern.Object pooling can provide a dramatic boost to an application's performance. Es kann jedoch auch einen gegenteiligen Effekt haben, wenn es nicht ordnungsgemäß verwendet wird.However, it can have the opposite effect if it is not used properly. Objektpooling hilft dabei, den Mehraufwand zu reduzieren, der durch die Neuerstellung häufig verwendeter Objekte, die eine umfangreiche Initialisierung erfordern, entsteht.Object pooling helps reduce the overhead of recreating frequently used objects that require extensive initialization. Wenn das Aufrufen einer Methode in einem gepoolten Objekt jedoch sehr lange dauert, werden durch das Objektpooling zusätzliche Anforderungen in einer Warteschlange platziert, sobald die maximale Poolgröße erreicht ist.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. Daher werden u. U. einige Anforderungen zur Objekterstellung nicht erfüllt, indem eine Timeoutausnahme ausgelöst wird.Thus it may fail to serve some object creation requests by throwing a timeout exception.

Hinweis

Die Setupprozedur und die Buildanweisungen für dieses Beispiel befinden sich am Ende dieses Themas.The setup procedure and build instructions for this sample are located at the end of this topic.

Der erste Schritt beim Erstellen einer WCF-Erweiterung ist die zu verwendenden Erweiterungspunkt entscheiden.The first step in creating a WCF extension is to decide the extensibility point to use.

In WCF der Begriff Dispatcher bezieht sich auf eine Laufzeitkomponente verantwortlich, konvertieren eingehende Nachrichten in Methodenaufrufe für den Dienst des Benutzers konvertiert und Rückgabewerte von dieser Methode in eine ausgehende Nachricht.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. Ein WCF-Dienst erstellt einen Verteiler für jeden Endpunkt.A WCF service creates a dispatcher for each endpoint. Wenn der diesem Client zugeordnete Vertrag einen Duplexvertrag handelt, muss ein WCF-Client einen Verteiler verwenden.A WCF client must use a dispatcher if the contract associated with that client is a duplex contract.

Der Kanal- und der Endpunktverteiler bieten eine kanal- und vertragsweite Erweiterbarkeit, indem sie verschiedene Eigenschaften, die das Verhalten des Verteilers steuern, verfügbar machen.The channel and endpoint dispatchers offer channel-and contract-wide extensibility by exposing various properties that control the behavior of the dispatcher. Die DispatchRuntime-Eigenschaft ermöglicht es Ihnen außerdem, den Verteilungsprozess zu überprüfen, zu ändern oder anzupassen.The DispatchRuntime property also enables you to inspect, modify, or customize the dispatching process. In diesem Beispiel wird in erster Linie die InstanceProvider-Eigenschaft behandelt, die auf das Objekt zeigt, das die Instanzen der Dienstklasse bereitstellt.This sample focuses on the InstanceProvider property that points to the object that provides the instances of the service class.

Der IInstanceProviderThe IInstanceProvider

In WCF, erstellt der Verteiler Instanzen der Klasse für den Dienst mithilfe einer InstanceProvider, implementiert die IInstanceProvider Schnittstelle.In WCF, the dispatcher creates instances of the service class using a InstanceProvider, which implements the IInstanceProvider interface. Diese Schnittstelle verfügt über drei Methoden:This interface has three methods:

Der ObjektpoolThe Object Pool

Eine benutzerdefinierte IInstanceProvider-Implementierung stellt die erforderliche Objektpoolingsemantik für einen Dienst bereit.A custom IInstanceProvider implementation provides the required object pooling semantics for a service. Deshalb verfügt dieses Beispiel über einen ObjectPoolingInstanceProvider-Typ, der eine benutzerdefinierte Implementierung von IInstanceProvider für das Pooling bereitstellt.Therefore, this sample has an ObjectPoolingInstanceProvider type that provides custom implementation of IInstanceProvider for pooling. Wenn der Dispatcher die GetInstance(InstanceContext, Message)-Methode aufruft, erstellt die benutzerdefinierte Implementierung keine neue Instanz, sondern sucht ein vorhandenes Objekt in einem Speicherpool.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. Wenn eines verfügbar ist, wird es zurückgegeben.If one is available, it is returned. Andernfalls wird ein neues Objekt erstellt.Otherwise, a new object is created. Die Implementierung für GetInstance wird im folgenden Beispielcode dargestellt.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;            
}  

Die benutzerdefinierte ReleaseInstance-Implementierung fügt die freigegebene Instanz dem Pool erneut hinzu und dekrementiert den ActiveObjectsCount-Wert.The custom ReleaseInstance implementation adds the released instance back to the pool and decrements the ActiveObjectsCount value. Der Dispatcher kann diese Methoden von unterschiedlichen Threads aus aufrufen. Daher ist ein synchronisierter Zugriff auf die Member der Klassenebene in der ObjectPoolingInstanceProvider-Klasse erforderlich.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();                       
    }  
}  

Die ReleaseInstance Methode stellt eine Funktion "bereinigungsinitialisierung" bereit.The ReleaseInstance method provides a "clean up initialization" feature. Normalerweise wird im Pool eine Mindestanzahl von Objekten für die Lebensdauer des Pools beibehalten.Normally the pool maintains a minimum number of objects for the lifetime of the pool. Es kann jedoch Zeiten mit übermäßiger Auslastung geben, für die im Pool zusätzliche Objekte erstellt werden müssen, um die in der Konfiguration festgelegte Höchstgrenze zu erreichen.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. Wenn der Pool weniger aktiv ist, stellen diese überzähligen Objekte einen zusätzlichen Aufwand dar.Eventually, when the pool becomes less active, those surplus objects can become an extra overhead. Wenn activeObjectsCount daher 0 (null) erreicht, wird ein Leerlaufzeitgeber gestartet, der einen Bereinigungszyklus auslöst und ausführt.Therefore, when the activeObjectsCount reaches zero, an idle timer is started that triggers and performs a clean-up cycle.

Hinzufügen des VerhaltensAdding the Behavior

Verteilerschicht-Erweiterungen werden mithilfe der folgenden Verhaltensweisen verknüpft:Dispatcher-layer extensions are hooked up using the following behaviors:

  • Dienstverhaltensweisen.Service Behaviors. Diese ermöglichen die Anpassung der gesamten Dienstlaufzeit.These allow for the customization of the entire service runtime.

  • Endpunktverhaltensweisen.Endpoint Behaviors. Diese ermöglichen die Anpassung von Dienstendpunkten, insbesondere eines Kanal- und Endpunktverteilers.These allow for the customization of service endpoints, specifically a Channel and Endpoint Dispatcher.

  • Vertragsverhaltensweisen.Contract Behaviors. Diese ermöglichen die Anpassung sowohl der ClientRuntime-Klasse als auch der DispatchRuntime-Klasse im Client bzw. Dienst.These allow for the customization of both ClientRuntime and DispatchRuntime classes on the client and the service respectively.

Für den Zweck einer Objektpoolingerweiterung muss ein Dienstverhalten erstellt werden.For the purpose of an object pooling extension a service behavior must be created. Dienstverhaltensweisen werden durch Implementieren der IServiceBehavior-Schnittstelle erstellt.Service behaviors are created by implementing the IServiceBehavior interface. Es gibt mehrere Möglichkeiten, das Dienstmodell auf die benutzerdefinierten Verhaltensweisen hinzuweisen:There are several ways to make the service model aware of the custom behaviors:

  • Verwenden eines benutzerdefinierten Attributs.Using a custom attribute.

  • Imperatives Hinzufügen zur Verhaltensauflistung der Dienstbeschreibung.Imperatively adding it to the service description’s behaviors collection.

  • Erweitern der Konfigurationsdatei.Extending the configuration file.

In diesem Beispiel wird ein benutzerdefiniertes Attribut verwendet.This sample uses a custom attribute. Beim Erstellen von ServiceHost werden die in der Typdefinition des Diensts verwendeten Attribute untersucht, und die verfügbaren Verhaltensweisen werden der Verhaltensauflistung der Dienstbeschreibung hinzugefügt.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.

Die Schnittstelle IServiceBehavior verfügt über drei Methoden – Validate, AddBindingParameters und ApplyDispatchBehavior.The interface IServiceBehavior has three methods in it -- Validate, AddBindingParameters, and ApplyDispatchBehavior. Die Validate-Methode wird verwendet, um sicherzustellen, dass das Verhalten für den Dienst übernommen werden kann.The Validate method is used to ensure that the behavior can be applied to the service. In diesem Beispiel stellt die Implementierung sicher, dass der Dienst nicht mit Single konfiguriert wird.In this sample, the implementation ensures that the service is not configured with Single. Die AddBindingParameters-Methode dient dazu, die Bindungen des Diensts zu konfigurieren.The AddBindingParameters method is used to configure the service's bindings. Sie ist für dieses Szenario nicht erforderlich.It is not required in this scenario. ApplyDispatchBehavior wird dazu verwendet, die Verteiler des Diensts zu konfigurieren.The ApplyDispatchBehavior is used to configure the service's dispatchers. Diese Methode wird aufgerufen, indem Sie WCF bei der ServiceHost initialisiert wird.This method is called by WCF when the ServiceHost is being initialized. Die folgenden Parameter werden an diese Methode übergeben:The following parameters are passed into this method:

  • Description: Dieses Argument stellt die Dienstbeschreibung für den gesamten Dienst bereit.Description: This argument provides the service description for the entire service. Dies kann dazu verwendet werden, Beschreibungsdaten über die Endpunkte, Verträge und Bindungen des Diensts und andere Daten zu überprüfen.This can be used to inspect description data about the service’s endpoints, contracts, bindings, and other data.

  • ServiceHostBase: Dieses Argument stellt die ServiceHostBase bereit, die gerade initialisiert wird.ServiceHostBase: This argument provides the ServiceHostBase that is currently being initialized.

In der benutzerdefinierten IServiceBehavior-Implementierung wird eine neue Instanz von ObjectPoolingInstanceProvider instanziiert und der InstanceProvider-Eigenschaft in jeder DispatchRuntime in der ServiceHostBase zugewiesen.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))  
            {  
                if (throttle == null)  
                {  
                    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;  
     }  
}  

Neben einer IServiceBehavior-Implementierung verfügt die ObjectPoolingAttribute-Klasse über mehrere Member zum Anpassen des Objektpools mithilfe der Attributargumente.In addition to an IServiceBehavior implementation the ObjectPoolingAttribute class has several members to customize the object pool using the attribute arguments. Diese Members umfassen MaxPoolSize, MinPoolSize und CreationTimeout für die Übereinstimmung mit dem von .NET Enterprise Services bereitgestellten Objektpooling-Featuresatz.These members include MaxPoolSize, MinPoolSize, and CreationTimeout, to match the object pooling feature set provided by .NET Enterprise Services.

Objektpooling Verhalten kann jetzt an einen WCF-Dienst hinzugefügt werden, durch das Hinzufügen der dienstimplementierung mit dem neu erstellten, benutzerdefinierten ObjectPooling Attribut.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  
{  
  // …  
}  

Ausführen des BeispielsRunning the Sample

Das Beispiel veranschaulicht die Leistungsvorteile, die durch die Verwendung von Objektpooling in bestimmten Szenarios erzielt werden können.The sample demonstrates the performance benefits that can be gained by using object pooling in certain scenarios.

Die Dienstanwendung implementiert zwei Dienste, WorkService und ObjectPooledWorkService.The service application implements two services -- WorkService and ObjectPooledWorkService. Beide Dienste teilen dieselbe Implementierung. Sie erfordern beide eine kostenintensive Initialisierung und machen dann eine DoWork()-Methode verfügbar, die relativ billig ist.Both services share the same implementation -- they both require expensive initialization and then expose a DoWork() method that is relatively cheap. Der einzige Unterschied ist, dass für ObjectPooledWorkService ein Objektpooling konfiguriert ist: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.");  
    }          
}  

Wenn Sie den Client ausführen, stoppt er die Zeit, die benötigt wird, um WorkService 5-mal aufzurufen.When you run the client, it times calling the WorkService 5 times. Er stoppt dann die Zeit, die benötigt wird, um ObjectPooledWorkService 5-mal aufzurufen.It then times calling the ObjectPooledWorkService 5 times. Dann wird der Zeitunterschied angezeigt: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.  

Hinweis

Wenn der Client zum ersten Mal ausgeführt wird, scheinen beide Dienste etwa gleich viel Zeit zu benötigen.The first time the client is run both services appear to take about the same amount of time. Wenn Sie das Beispiel erneut ausführen, können Sie sehen, dass ObjectPooledWorkService wesentlich schneller zurückkehrt, da im Pool bereits eine Instanz dieses Objekts vorhanden ist.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.

So können Sie das Beispiel einrichten, erstellen und ausführenTo set up, build, and run the sample

  1. Stellen Sie sicher, dass Sie ausgeführt haben die Setupprozedur für die Windows Communication Foundation-Beispiele zum einmaligen.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. Führen Sie zum Erstellen der Projektmappe die Anweisungen im Erstellen der Windows Communication Foundation-Beispiele.To build the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. Um das Beispiel in einer einzelnen oder computerübergreifenden Konfiguration ausführen möchten, folgen Sie den Anweisungen Ausführen der Windows Communication Foundation-Beispiele.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Hinweis

Wenn Sie zur Neugenerierung der Konfiguration für dieses Beispiel die Datei Svcutil.exe verwenden, müssen Sie den Endpunktnamen in der Clientkonfiguration so ändern, dass er mit dem Clientcode übereinstimmt.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.

Wichtig

Die Beispiele sind möglicherweise bereits auf dem Computer installiert.The samples may already be installed on your machine. Suchen Sie nach dem folgenden Verzeichnis (Standardverzeichnis), bevor Sie fortfahren.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Wenn dieses Verzeichnis nicht vorhanden ist, fahren Sie mit Windows Communication Foundation (WCF) und Windows Workflow Foundation (WF) Samples for .NET Framework 4 aller Windows Communication Foundation (WCF) herunterladen und WFWF Beispiele.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. Dieses Beispiel befindet sich im folgenden Verzeichnis.This sample is located in the following directory.

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

Siehe auchSee Also