ลดความจุของ Semaphore แบบไดนามิก

ฉันพยายามใช้เซมาฟอร์เพื่อควบคุมจำนวนคำขอที่บริการของฉันสามารถรองรับได้ เช่น.

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

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

มีปัญหา 2 ประการที่ฉันพบซึ่งฉันไม่แน่ใจว่าจะแก้ไขอย่างไร ฉันใช้แฮ็กที่คล้ายกันเพื่อแก้ไขปัญหาเหล่านี้ แต่ฉันสงสัยว่ามีวิธีใดที่ดีกว่านี้หรือไม่

  1. ฉันต้องการที่จะเปลี่ยนแปลงขีดความสามารถของคลาสบริการของฉันแบบไดนามิก ดังนั้นฉันจึงมีสิ่งนี้

    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. ที่วิธีการกำจัด ฉันต้องการให้แน่ใจว่าการประมวลผลคำขอทั้งหมดเสร็จสมบูรณ์ก่อนที่ฉันจะกำจัดเซมาฟอร์ ไม่เช่นนั้นการเรียก s.Release() ใน ProcessRequest() ของฉันจะส่ง ObjectDisposedException ดังนั้นฉันจึงทำสิ่งต่อไปนี้

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

โปรดทราบว่าฉันใช้การวนซ้ำเพื่อรอด้วยตนเองหลายครั้ง นี่จะช้ามากหากความจุมีขนาดใหญ่ มีวิธีที่ดีกว่าในการทำเช่นนี้หรือไม่? มี Release(int count) สำหรับเซมาฟอร์ ทำไมไม่มี Wait(int count)?


person user1763590    schedule 06.12.2013    source แหล่งที่มา
comment
ฉันได้แก้ไขชื่อของคุณแล้ว โปรดดูที่ คำถามควรใส่ "แท็ก" ในชื่อหรือไม่ ในกรณีที่ไม่มีมติ ก็ไม่ควร   -  person John Saunders    schedule 06.12.2013


คำตอบ (1)


สิ่งที่ฉันน่าจะทำคือเมื่อทำการปรับเปลี่ยนแล้ว แทนที่อินสแตนซ์เซมาฟอร์ของคุณด้วยเซมาฟอร์ใหม่ที่มีความจุที่ต้องการ และมอบหมายงานในอนาคตทั้งหมดให้กับเซมาฟอร์นั้น เซมาฟอร์ที่มีอยู่และขณะนี้ถูกยกเลิกการอ้างอิงจะไม่ถูกรวบรวมจนกว่าเธรดทั้งหมดจะเสร็จสิ้นโดยอ้างอิง ดังนั้น จึงควรดำเนินการได้อย่างปลอดภัยตราบใดที่คุณกำหนดตัวแปรเซมาฟอร์ภายในเครื่องให้กับแต่ละเธรด

person Haney    schedule 06.12.2013
comment
ขอบคุณ แต่นี่จะแก้ปัญหาแรกของฉันเท่านั้น ไม่ใช่ปัญหาที่สองใช่ไหม นอกจากนี้ หากเราจะแลก Semaphore เราก็ต้องทำให้มันผันผวนใช่ไหม? สิ่งนี้จะทำให้คำขอปกติช้าลงในการดำเนินการที่หายากเหล่านี้... นี่คือสาเหตุที่ฉันไม่ได้ทำการแลกเปลี่ยนตั้งแต่แรก - person user1763590; 06.12.2013
comment
ลองคิดดูอีกสักหน่อย ดูเหมือนว่าความผันผวนยังไม่เพียงพอ เราควรจะต้องล็อคมันไว้เพราะการสร้างเซมาฟอร์ใหม่ต้องใช้เวลาและในระหว่างการสร้างสถานะของเซมาฟอร์ดั้งเดิมอาจเปลี่ยนแปลง... ดังนั้นฉันเดาว่าวิธีแก้ปัญหานี้คงไม่ได้ผลสำหรับฉันเลย - person user1763590; 07.12.2013
comment
คุณไม่จำเป็นต้องล็อคมัน นี่คือแนวคิดของการประเมินอย่างกระตือรือร้น หากฉันกำหนดตัวแปรแบบโลคัลเมื่อเริ่มต้นวิธีการของฉัน เธรดอื่นสามารถเปลี่ยนการอ้างอิงดั้งเดิมที่ฉันกำหนดได้ และตัวแปรในเครื่องของฉันยังคงเป็นการอ้างอิงเดียวกัน คุณต้องการความผันผวนที่นี่เพื่อให้แน่ใจว่าคอมไพเลอร์ไม่ได้ปรับการมอบหมายให้เหมาะสม ในแง่ของปัญหา #2 (การแยกส่วน) คุณไม่ควรเรียก Dispose จนกว่าอินสแตนซ์ทั้งหมดของคุณจะเสร็จสิ้น พิจารณาสถาปัตยกรรมของคุณเนื่องจาก Dispose มีไว้สำหรับทรัพยากรที่ไม่มีการจัดการ ไม่ใช่ตรรกะทางธุรกิจที่ได้รับการจัดการ - person Haney; 07.12.2013