Mengurangi kapasitas Semaphore secara dinamis

Saya telah mencoba menggunakan Semaphore untuk mengontrol jumlah permintaan yang dapat ditangani oleh layanan saya. YAITU.

class Service : IDisposable {
    SemaphoreSlim s = new SemaphoreSlim(InitialCapacity);

    ....
    async void ProcessRequest() {
        await s.WaitAsync();
        try {
             ......
        } finally {
            s.Release();
        }
    }
}

Ada 2 masalah yang saya temui yang saya tidak yakin bagaimana menyelesaikannya. Saya telah menggunakan peretasan serupa untuk menyelesaikan masalah ini, tetapi saya ingin tahu apakah ada cara yang lebih baik

  1. Saya ingin dapat mengubah kapasitas kelas layanan saya secara dinamis, jadi saya punya sesuatu seperti ini.

    void ChangeCapacity(int newCapacity) {
        int extraRequestsCount = newCapacity - oldCapacity;
        if (extraRequestsCount > 0) {
            s.Release(extraRequestsCount);
        }
        else if (extraRequestsCount < 0) {
            for (int i = 0; i < -extraRequestsCount; i++) {
                s.WaitAsync(); // try to steal some resources, over time...
            }
        }
    }
    
  2. Pada metode buang, saya ingin memastikan semua pemrosesan permintaan selesai sebelum saya membuang semaphore, jika tidak, panggilan s.Release() di ProcessRequest() saya akan memunculkan ObjectDisposeException jadi saya melakukan hal berikut

    public void Dispose() {
        if (s!= null) {
            for (int i = 0; i < oldCapacity; i++) {
                s.Wait();
            }
            s.Dispose();
        }
    }
    

Perhatikan bahwa saya telah menggunakan loop untuk menunggu secara manual berkali-kali. Ini sangat lambat jika kapasitasnya besar. Apakah ada cara yang lebih baik untuk melakukan ini? Ada Rilis(int count) untuk semaphore mengapa tidak ada Wait(int count)?


person user1763590    schedule 06.12.2013    source sumber
comment
Saya telah mengedit judul Anda. Silakan lihat, Haruskah pertanyaan menyertakan “tag” di judulnya?, jika konsensusnya tidak, maka pertanyaan tersebut tidak boleh disertakan.   -  person John Saunders    schedule 06.12.2013


Jawaban (1)


Apa yang mungkin saya lakukan adalah ketika penyesuaian dilakukan, ganti instance semaphore Anda dengan semaphore baru dengan kapasitas yang diinginkan, dan tetapkan semua pekerjaan di masa depan ke semaphore itu. Semaphore yang ada dan yang sekarang sudah didereferensi tidak akan dikumpulkan dari sampah sampai semua thread selesai mereferensikannya, jadi sebaiknya aman melakukan ini selama Anda menetapkan variabel semaphore secara lokal ke setiap thread.

person Haney    schedule 06.12.2013
comment
Terima kasih, tapi ini hanya akan menyelesaikan masalah pertama saya, bukan masalah kedua? Selain itu, jika kita menukar Semaphore, kita harus membuatnya mudah berubah, bukan? ini akan membuat permintaan normal lebih lambat dalam operasi yang lebih jarang ini... inilah mengapa saya tidak melakukan pertukaran sejak awal - person user1763590; 06.12.2013
comment
Kalau dipikir-pikir lagi, sepertinya volatilitas saja tidak cukup. Kita harus menguncinya karena membuat semafor baru membutuhkan waktu dan selama pembuatan, keadaan semafor asli dapat berubah... jadi saya kira solusi ini tidak akan berhasil untuk saya sama sekali - person user1763590; 07.12.2013
comment
Anda tidak perlu menguncinya. Ini adalah konsep evaluasi yang bersemangat. Jika saya menetapkan variabel secara lokal di awal metode saya, thread lain dapat mengubah referensi asli yang saya tetapkan dan variabel lokal saya tetap menjadi referensi yang sama. Anda ingin volatil di sini untuk memastikan kompiler tidak mengoptimalkan penugasan. Dalam hal masalah #2 (spindown), Anda tidak boleh memanggil Buang SAMPAI semua instans Anda selesai. Pertimbangkan arsitektur Anda karena Dispose ditujukan untuk sumber daya yang tidak dikelola, bukan logika bisnis yang dikelola. - person Haney; 07.12.2013