Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Sampel Pooling menunjukkan cara memperluas Windows Communication Foundation (WCF) untuk mendukung pengumpulan objek. Sampel menunjukkan cara membuat atribut yang secara sintetis dan semantik mirip ObjectPoolingAttribute dengan fungsionalitas atribut Enterprise Services. Pengumpulan objek dapat memberikan peningkatan dramatis pada performa aplikasi. Namun, itu dapat memiliki efek yang berlawanan jika tidak digunakan dengan benar. Pengumpulan objek membantu mengurangi overhead pembuatan ulang objek yang sering digunakan yang memerlukan inisialisasi ekstensif. Namun, jika panggilan ke metode pada objek yang dalam kumpulan memerlukan waktu yang cukup lama untuk diselesaikan, pemrosesan objek akan mengantrekan permintaan baru segera setelah ukuran kumpulan maksimum tercapai. Dengan demikian, mungkin gagal melayani sejumlah permintaan pembuatan objek dengan mengeluarkan pengecualian waktu habis.
Nota
Prosedur penyiapan dan instruksi build untuk sampel ini terletak di akhir topik ini.
Langkah pertama dalam membuat ekstensi WCF adalah memutuskan titik ekstensibilitas yang akan digunakan.
Di WCF istilah dispatcher mengacu pada komponen runtime yang bertanggung jawab untuk mengonversi pesan masuk menjadi pemanggilan metode pada layanan pengguna dan untuk mengonversi nilai pengembalian dari metode tersebut ke pesan keluar. Layanan WCF membuat dispatcher untuk setiap titik akhir. Klien WCF harus menggunakan dispatcher jika kontrak yang terkait dengan klien tersebut adalah kontrak dupleks.
Dispatcher kanal dan titik akhir menawarkan ekstensibilitas menyeluruh untuk kanal dan kontrak dengan memaparkan berbagai properti yang mengontrol perilaku dispatcher. Properti ini DispatchRuntime juga memungkinkan Anda memeriksa, memodifikasi, atau menyesuaikan proses pengiriman. Sampel ini berfokus pada properti InstanceProvider yang menunjuk ke objek yang menyediakan instans kelas layanan.
The IInstanceProvider
Di WCF, dispatcher membuat instans kelas layanan menggunakan InstanceProvider, yang mengimplementasikan antarmuka IInstanceProvider. Antarmuka ini memiliki tiga metode:
GetInstance(InstanceContext, Message): Ketika pesan tiba, Dispatcher memanggil metode untuk membuat instans GetInstance(InstanceContext, Message) kelas layanan untuk memproses pesan. Frekuensi panggilan ke metode ini ditentukan oleh properti InstanceContextMode. Misalnya, jika InstanceContextMode properti diatur ke PerCall instans baru kelas layanan dibuat untuk memproses setiap pesan yang tiba, jadi GetInstance(InstanceContext, Message) dipanggil setiap kali pesan tiba.
GetInstance(InstanceContext): Ini identik dengan metode sebelumnya, kecuali ini dipanggil ketika tidak ada argumen Pesan.
ReleaseInstance(InstanceContext, Object): Ketika masa pakai instans layanan telah berlalu, Dispatcher memanggil ReleaseInstance(InstanceContext, Object) metode . Sama seperti untuk metode GetInstance(InstanceContext, Message), frekuensi panggilan ke metode ini ditentukan oleh properti InstanceContextMode.
Kumpulan Objek
Implementasi kustom IInstanceProvider menyediakan semantik pengumpulan objek yang diperlukan untuk layanan. Oleh karena itu, sampel ini memiliki jenis ObjectPoolingInstanceProvider yang menyediakan implementasi kustom IInstanceProvider untuk pooling. Ketika Dispatcher memanggil metode GetInstance(InstanceContext, Message), implementasi kustom tidak membuat instans baru, melainkan mencari objek yang sudah ada di kumpulan memori. Jika ada yang tersedia, maka akan dikembalikan. Jika tidak, objek baru dibuat. Implementasi untuk GetInstance ditunjukkan dalam kode sampel berikut.
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;
}
Implementasi ReleaseInstance khusus menambahkan kembali instans yang dirilis ke kumpulan dan mengurangi nilai ActiveObjectsCount.
Dispatcher dapat memanggil metode ini dari utas yang berbeda, dan oleh karena itu akses yang disinkronkan ke anggota tingkat kelas pada kelas ObjectPoolingInstanceProvider diperlukan.
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();
}
}
Metode ReleaseInstance menyediakan fitur "pembersihan inisialisasi". Biasanya pool mempertahankan jumlah minimum objek selama masa hidup pool. Namun, terdapat kemungkinan terjadinya periode penggunaan berlebihan yang memerlukan pembuatan objek tambahan di dalam kumpulan untuk memenuhi batas maksimum yang ditentukan dalam konfigurasi. Akhirnya, ketika kolam menjadi kurang aktif, objek-objek surplus tersebut dapat menjadi beban tambahan. Oleh karena itu, ketika activeObjectsCount mencapai nol, timer diam dimulai yang memicu dan melakukan siklus pembersihan.
Menambahkan Perilaku
Ekstensi lapisan dispatcher dikaitkan menggunakan perilaku berikut:
Perilaku Layanan. Ini memungkinkan penyesuaian seluruh runtime layanan.
Perilaku Titik Akhir. Ini memungkinkan penyesuaian titik akhir layanan, khususnya Dispatcher Saluran dan Titik Akhir.
Tingkah Laku Kontrak. Ini memungkinkan penyesuaian kelas ClientRuntime pada klien dan kelas DispatchRuntime pada layanan masing-masing.
Untuk tujuan ekstensi pengumpulan objek, perilaku layanan harus dibuat. Perilaku layanan dibuat dengan menerapkan antarmuka IServiceBehavior. Ada beberapa cara untuk membuat model layanan mengetahui perilaku kustom:
Menggunakan atribut kustom.
Secara imperatif menambahkannya ke kumpulan perilaku deskripsi layanan.
Memperluas file konfigurasi.
Sampel ini menggunakan atribut kustom. ServiceHost Ketika dibangun, ia memeriksa atribut yang digunakan dalam definisi jenis layanan dan menambahkan perilaku yang tersedia ke koleksi perilaku deskripsi layanan.
Antarmuka IServiceBehavior memiliki tiga metode di dalamnya -- Validate, , AddBindingParametersdan ApplyDispatchBehavior. Metode Validate ini digunakan untuk memastikan bahwa perilaku dapat diterapkan ke layanan. Dalam sampel ini, implementasi memastikan bahwa layanan tidak dikonfigurasi dengan Single. Metode AddBindingParameters ini digunakan untuk mengonfigurasi pengikatan layanan. Ini tidak diperlukan dalam skenario ini. ApplyDispatchBehavior digunakan untuk mengonfigurasi dispatcher layanan. Metode ini dipanggil oleh WCF ketika ServiceHost sedang diinisialisasi. Parameter berikut diteruskan ke metode ini:
Description: Argumen ini menyediakan deskripsi layanan untuk seluruh layanan. Ini dapat digunakan untuk memeriksa data deskripsi tentang titik akhir layanan, kontrak, pengikatan, dan data lainnya.ServiceHostBase: Argumen ini menyediakan ServiceHostBase yang saat ini sedang diinisialisasi.
Dalam implementasi kustom IServiceBehavior, instance ObjectPoolingInstanceProvider baru dibuat dan ditetapkan ke properti InstanceProvider di masing-masing DispatchRuntime di 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;
}
}
Selain IServiceBehavior implementasi kelas ObjectPoolingAttribute memiliki beberapa anggota untuk menyesuaikan kumpulan objek menggunakan argumen atribut. Anggota ini termasuk MaxPoolSize, MinPoolSize, dan CreationTimeout, untuk mencocokkan sekumpulan fitur pooling objek yang disediakan oleh .NET Enterprise Services.
Perilaku kumpulan objek sekarang dapat ditambahkan ke layanan WCF dengan memberi anotasi pada implementasi layanan dengan atribut ObjectPooling khusus yang baru dibuat.
[ObjectPooling(MaxPoolSize=1024, MinPoolSize=10, CreationTimeout=30000)]
public class PoolService : IPoolService
{
// …
}
Menjalankan sampel
Sampel menunjukkan manfaat performa yang dapat diperoleh dengan menggunakan pengumpulan objek dalam skenario tertentu.
Aplikasi layanan mengimplementasikan dua layanan -- WorkService dan ObjectPooledWorkService. Kedua layanan tersebut memiliki implementasi yang sama -- keduanya memerlukan inisialisasi yang mahal dan kemudian mengekspos metode DoWork() yang relatif murah. Satu-satunya perbedaan adalah bahwa ObjectPooledWorkService memiliki pooling objek yang dikonfigurasi.
[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.");
}
}
Ketika Anda menjalankan klien, itu menghitung waktu saat memanggil WorkService sebanyak 5 kali. Kemudian melakukan pemanggilan ObjectPooledWorkService sebanyak 5 kali. Perbedaan waktu kemudian ditampilkan:
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.
Nota
Pertama kali klien menjalankan kedua layanan tampaknya membutuhkan waktu yang sama. Jika Anda menjalankan ulang sampelnya, Anda dapat melihat bahwa ObjectPooledWorkService pengembaliannya jauh lebih cepat karena instans objek tersebut sudah ada dalam kumpulan.
Untuk menyiapkan, mengompilasi, dan menjalankan sampel
Pastikan Anda telah melakukan Prosedur Penyiapan One-Time untuk Sampel Windows Communication Foundation.
Untuk membangun solusi, ikuti instruksi dalam Membangun Sampel Windows Communication Foundation.
Untuk menjalankan sampel dalam konfigurasi satu atau lintas komputer, ikuti instruksi di Menjalankan Sampel Windows Communication Foundation.
Nota
Jika Anda menggunakan Svcutil.exe untuk meregenerasi konfigurasi untuk sampel ini, pastikan untuk mengubah nama titik akhir dalam konfigurasi klien agar sesuai dengan kode klien.