Biriktirme
Havuz örneği, nesne havuzunu desteklemek için Windows Communication Foundation'ı (WCF) genişletmeyi gösterir. Örnek, Kurumsal Hizmetler'in öznitelik işlevselliğine benzer söz dizimsel ve anlamsal olarak benzer bir özniteliğin ObjectPoolingAttribute
nasıl oluşturulacağını gösterir. Nesne havuzu, bir uygulamanın performansını önemli ölçüde artırabilir. Ancak, düzgün kullanılmazsa tam tersi bir etkiye sahip olabilir. Nesne havuzu, kapsamlı başlatma gerektiren sık kullanılan nesneleri yeniden oluşturma yükünü azaltmaya yardımcı olur. Ancak, havuza alınmış bir nesnedeki bir yönteme yapılan çağrının tamamlanması çok uzun sürüyorsa, nesne havuzu oluşturma en büyük havuz boyutuna ulaşıldığında ek istekleri kuyruğa alır. Bu nedenle, zaman aşımı özel durumu oluşturarak bazı nesne oluşturma isteklerine hizmet vermeyebilir.
Not
Bu örnek için kurulum yordamı ve derleme yönergeleri bu konunun sonunda yer alır.
WCF uzantısı oluşturmanın ilk adımı, kullanılacak genişletilebilirlik noktasına karar vermektir.
WCF'de dağıtıcı terimi, gelen iletileri kullanıcının hizmetinde yöntem çağrılarına dönüştürmekten ve dönüş değerlerini bu yöntemden giden iletiye dönüştürmekten sorumlu bir çalışma zamanı bileşenine başvurur. WCF hizmeti her uç nokta için bir dağıtıcı oluşturur. WcF istemcisiyle ilişkilendirilmiş sözleşme çift yönlü bir sözleşmeyse bir dağıtıcı kullanmalıdır.
Kanal ve uç nokta dağıtıcıları, dağıtıcının davranışını denetleyen çeşitli özellikleri kullanıma sunarak kanal ve sözleşme genelinde genişletilebilirlik sunar. DispatchRuntime özelliği ayrıca gönderme işlemini incelemenize, değiştirmenize veya özelleştirmenize de olanak tanır. Bu örnek, hizmet sınıfının örneklerini sağlayan nesneye işaret eden özelliğe odaklanır InstanceProvider .
The IInstanceProvider
WCF'de dağıtıcı, arabirimini uygulayan IInstanceProvider bir InstanceProviderkullanarak hizmet sınıfının örneklerini oluşturur. Bu arabirimin üç yöntemi vardır:
GetInstance(InstanceContext, Message): Bir ileti geldiğinde Dispatcher, iletiyi işlemek için hizmet sınıfının bir örneğini oluşturmak için yöntemini çağırır GetInstance(InstanceContext, Message) . Bu yönteme yapılan çağrıların sıklığı özelliği tarafından InstanceContextMode belirlenir. Örneğin, özelliği yeni bir hizmet sınıfı örneğine PerCall ayarlanırsaInstanceContextMode, gelen her iletiyi işlemek için oluşturulur, bu nedenle GetInstance(InstanceContext, Message) her ileti geldiğinde çağrılır.
GetInstance(InstanceContext): Bu, önceki yöntemle aynıdır, ancak İleti bağımsız değişkeni olmadığında bu çağrılır.
ReleaseInstance(InstanceContext, Object): Hizmet örneğinin ömrü geçtiğinde Dispatcher yöntemini çağırır ReleaseInstance(InstanceContext, Object) . Yönteminde GetInstance(InstanceContext, Message) olduğu gibi, bu yönteme yapılan çağrıların sıklığı özelliği tarafından InstanceContextMode belirlenir.
Nesne Havuzu
Özel IInstanceProvider bir uygulama, bir hizmet için gerekli nesne havuzu semantiğini sağlar. Bu nedenle, bu örnek havuz için özel uygulaması IInstanceProvider sağlayan bir ObjectPoolingInstanceProvider
türe sahiptir. Dispatcher
yeni bir örnek oluşturmak yerine yöntemini çağırdığındaGetInstance(InstanceContext, Message), özel uygulama bellek içi havuzda var olan bir nesneyi arar. Varsa, döndürülür. Aksi takdirde yeni bir nesne oluşturulur. uygulaması GetInstance
aşağıdaki örnek kodda gösterilmiştir.
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;
}
Özel ReleaseInstance
uygulama, serbest bırakılmış örneği havuza geri ekler ve değeri geri ActiveObjectsCount
alır. Dispatcher
bu yöntemleri farklı iş parçacıklarından çağırabilir ve bu nedenle sınıftaki sınıf düzeyi üyelerine ObjectPoolingInstanceProvider
eşitlenmiş erişim gereklidir.
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();
}
}
ReleaseInstance
yöntemi bir "başlatmayı temizleme" özelliği sağlar. Normalde havuz, havuzun ömrü boyunca en az sayıda nesne tutar. Ancak, yapılandırmada belirtilen üst sınıra ulaşmak için havuzda ek nesneler oluşturulmasını gerektiren aşırı kullanım dönemleri olabilir. Sonuç olarak, havuz daha az etkin hale geldiğinde, bu fazlalık nesneler ek yük haline gelebilir. Bu nedenle, sıfıra activeObjectsCount
ulaştığında, bir temizleme döngüsünü tetikleyen ve gerçekleştiren bir boşta zamanlayıcı başlatılır.
Davranış Ekleme
Dağıtıcı katmanı uzantıları aşağıdaki davranışlar kullanılarak bağlanır:
Hizmet Davranışları. Bunlar hizmet çalışma zamanının tamamını özelleştirmeye olanak tanır.
Uç Nokta Davranışları. Bunlar hizmet uç noktalarının, özellikle de Bir Kanal ve Uç Nokta Dağıtıcısının özelleştirilmesine olanak sağlar.
Sözleşme Davranışları. Bunlar, istemcide ve hizmette sırasıyla hem hem DispatchRuntime de ClientRuntime sınıfların özelleştirilmesine olanak sağlar.
Nesne havuzu uzantısının amacı için bir hizmet davranışı oluşturulmalıdır. Hizmet davranışları, arabirimi uygulanarak IServiceBehavior oluşturulur. Hizmet modelini özel davranışların farkında hale getirmenin birkaç yolu vardır:
Özel öznitelik kullanma.
Bunu hizmet açıklamasının davranış koleksiyonuna kesin olarak ekleme.
Yapılandırma dosyasını genişletme.
Bu örnek özel bir öznitelik kullanır. ServiceHost oluşturulduğunda, hizmetin tür tanımında kullanılan öznitelikleri inceler ve kullanılabilir davranışları hizmet açıklamasının davranış koleksiyonuna ekler.
Arabirimin IServiceBehavior içinde üç yöntem vardır: Validate, AddBindingParametersve ApplyDispatchBehavior. Validate yöntemi, davranışın hizmete uygulanamasını sağlamak için kullanılır. Bu örnekte, uygulama hizmetin ile Singleyapılandırılmamasını sağlar. AddBindingParameters yöntemi, hizmetin bağlamalarını yapılandırmak için kullanılır. Bu senaryoda gerekli değildir. ApplyDispatchBehavior, hizmetin dağıtıcılarını yapılandırmak için kullanılır. Bu yöntem, başlatılırken ServiceHost WCF tarafından çağrılır. Aşağıdaki parametreler bu yönteme geçirilir:
Description
: Bu bağımsız değişken, hizmetin tamamı için hizmet açıklamasını sağlar. Bu, hizmetin uç noktaları, sözleşmeleri, bağlamaları ve diğer verileri hakkındaki açıklama verilerini incelemek için kullanılabilir.ServiceHostBase
: Bu bağımsız değişken şu anda başlatılmakta ServiceHostBase olan öğesini sağlar.
Özel IServiceBehavior uygulamada yeni bir örneği ObjectPoolingInstanceProvider
oluşturulur ve ServiceHostBase'deki her DispatchRuntime bir özelliğine atanırInstanceProvider.
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;
}
}
Bir IServiceBehavior uygulamaya ek olarak, sınıfın ObjectPoolingAttribute öznitelik bağımsız değişkenlerini kullanarak nesne havuzunu özelleştirmek için birkaç üyesi vardır. Bu üyeler, .NET Enterprise Services tarafından sağlanan nesne havuzu özelliği kümesiyle eşleşmesi için , MinPoolSizeve CreationTimeoutiçerirMaxPoolSize.
Nesne havuzu oluşturma davranışı artık yeni oluşturulan özel ObjectPooling
öznitelikle hizmet uygulamasına ek açıklama eklenerek bir WCF hizmetine eklenebilir.
[ObjectPooling(MaxPoolSize=1024, MinPoolSize=10, CreationTimeout=30000)]
public class PoolService : IPoolService
{
// …
}
Örneği Çalıştırma
Örnek, belirli senaryolarda nesne havuzu kullanılarak elde edilebilecek performans avantajlarını gösterir.
Hizmet uygulaması iki hizmet uygular: WorkService
ve ObjectPooledWorkService
. Her iki hizmet de aynı uygulamayı paylaşır; her ikisi de pahalı başlatma gerektirir ve sonra nispeten ucuz bir DoWork()
yöntemi kullanıma sunar. Tek fark, nesne havuzunun ObjectPooledWorkService
yapılandırılmış olmasıdır:
[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.");
}
}
İstemciyi çalıştırdığınızda, 5 kez çağrılır WorkService
. Daha sonra 5 kez arar ObjectPooledWorkService
. Zaman farkı daha sonra görüntülenir:
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.
Not
İstemci ilk kez çalıştırıldığında her iki hizmet de yaklaşık aynı zaman alıyor gibi görünür. Örneği yeniden çalıştırırsanız, bu nesnenin ObjectPooledWorkService
bir örneği havuzda zaten var olduğundan çok daha hızlı döndürdüğünü görebilirsiniz.
Örneği ayarlamak, derlemek ve çalıştırmak için
Windows Communication Foundation Örnekleri için Tek Seferlik Kurulum Yordamı'nı gerçekleştirdiğinizden emin olun.
Çözümü oluşturmak için Windows Communication Foundation Örnekleri Oluşturma başlığındaki yönergeleri izleyin.
Örneği tek veya makineler arası bir yapılandırmada çalıştırmak için Windows Communication Foundation Örneklerini Çalıştırma başlığındaki yönergeleri izleyin.
Not
Bu örneğin yapılandırmasını yeniden oluşturmak için Svcutil.exe kullanıyorsanız, istemci yapılandırmasındaki uç nokta adını istemci koduyla eşleşecek şekilde değiştirdiğinizden emin olun.