SemaphoreSlim'in kullanımını anlamanız gerekiyor


95

İşte sahip olduğum kod ama ne SemaphoreSlimyaptığını anlamıyorum .

async Task WorkerMainAsync()
{
    SemaphoreSlim ss = new SemaphoreSlim(10);
    List<Task> trackedTasks = new List<Task>();
    while (DoMore())
    {
        await ss.WaitAsync();
        trackedTasks.Add(Task.Run(() =>
        {
            DoPollingThenWorkAsync();
            ss.Release();
        }));
    }
    await Task.WhenAll(trackedTasks);
}

void DoPollingThenWorkAsync()
{
    var msg = Poll();
    if (msg != null)
    {
        Thread.Sleep(2000); // process the long running CPU-bound job
    }
}

Ne bekliyor ss.WaitAsync();ve ss.Release();ne yapıyor?

Bir seferde 50 iş parçacığı çalıştırırsam, o zamanki gibi kod SemaphoreSlim ss = new SemaphoreSlim(10);yazarsam, aynı anda 10 aktif iş parçacığı çalıştırmak zorunda kalacak.

10 iş parçacığından biri tamamlandığında, başka bir iş parçacığı başlayacaktır. Eğer haklı değilsem, örnek durumu anlamama yardım et.

Neden awaitbirlikte gerekli ss.WaitAsync();? Ne yapar ss.WaitAsync();?


3
Unutulmaması gereken bir şey, gerçekten "DoPollingThenWorkAsync ();" "{DoPollingThenWorkAsync ();} sonunda {ss.Release ();} deneyin", aksi takdirde istisnalar o semaforu kalıcı olarak aç bırakacaktır.
Austin Salgat

Sırasıyla görevin dışında / içinde semaforu alıp bıraktığımız için biraz garip hissediyorum. "Await ss.WaitAsync ()" işlevinin görev içinde taşınması herhangi bir fark yaratır mı?
Shane Lu

Yanıtlar:


77

sanırım bir seferde 50 iş parçacığı çalıştırırsam SemaphoreSlim ss = new SemaphoreSlim (10) gibi kodlayın; aynı anda 10 aktif iş parçacığı çalıştırmaya zorlayacak

Bu doğru; semafor kullanımı, bu işi aynı anda yapan 10'dan fazla işçi olmamasını sağlar.

Semaforun çağrılması WaitAsync, o iş parçacığına o token'a "erişim" verildiğinde tamamlanacak bir görev üretir. await-bu göreve "izin verildiğinde" programın çalışmaya devam etmesini sağlar. Çağırmak yerine zaman uyumsuz bir sürüme sahip olmak, Waithem yöntemin eşzamanlı olmaktan ziyade eşzamansız kalmasını sağlamak hem asyncde geri aramalar nedeniyle bir yöntemin birkaç iş parçacığı boyunca kod çalıştırabileceği gerçeğiyle ilgilenmek açısından önemlidir. semaforlarla doğal iplik yakınlığı bir problem olabilir.

Bir yan not: postfix DoPollingThenWorkAsyncolmamalıdır Asyncçünkü aslında eşzamansız değil, eşzamanlıdır. Sadece ara DoPollingThenWork. Okuyucular için kafa karışıklığını azaltacaktır.


teşekkürler ama lütfen bana 10 iş parçacığından biri bittiğinde 10 iş parçacığından biri bittiğinde başka bir işi bitirmek veya havuza geri döndüğünde hiçbir iş parçacığı belirtmediğimizde ne olacağını söyle. bu çok açık değil .... bu yüzden lütfen sahnenin arkasında ne olduğunu açıklayın.
Mou

@Mou Bu konuda net olmayan nedir? Kod, şu anda çalışan 10'dan az görev olana kadar bekler; olduğu zaman, bir başkasını ekler. Bir görev bittiğinde, bittiğini gösterir. Bu kadar.
2013

çalıştırılacak iş parçacığı yok belirtmenin avantajı nedir? çok fazla iş parçacığı performansı engelleyebilirse? evet ise o zaman neden engel ... 10 iş parçacığı yerine 50 iş parçacığı çalıştırırsam performans neden önemli olacak ... lütfen açıklayabilir misiniz? teşekkürler
Thomas

4
@Thomas Çok fazla eşzamanlı iş parçacığınız varsa, iş parçacıkları üretken iş yapmak için harcadıklarından daha fazla zaman bağlamı değiştirir. İş yapmak yerine iş parçacıkları yönetmek için daha fazla zaman harcadıkça, en azından iş parçacığı sayınız makinedeki çekirdek sayısının çok üzerine çıktığında, iş parçacığı arttıkça verim azalır.
2013,

3
@Servy Bu, görev planlayıcının işinin bir parçasıdır. Görevler! = İş parçacıkları. Thread.SleepOrijinal kodunda görev zamanlayıcı harap olacaktır. Çekirdek ile eşzamansız değilseniz, eşzamansız değilsinizdir.
Joseph Lennox

67

Köşedeki anaokulunda beden eğitimi odasında kaç çocuğun oynayabileceğini kontrol etmek için bir SemaphoreSlim kullanıyorlar.

Yerde, odanın dışında, 5 çift ayak izi boyadılar.

Çocuklar geldiğinde, ayakkabılarını serbest bir çift ayak izine bırakıp odaya girerler.

Oyun bittikten sonra dışarı çıkarlar, ayakkabılarını toplarlar ve başka bir çocuk için bir yuva "serbest bırakırlar".

Bir çocuk gelirse ve ayak izi kalmazsa, başka bir yerde oynarlar veya bir süre etrafta kalırlar ve ara sıra kontrol ederler (yani, FIFO öncelikleri yoktur).

Bir öğretmen etrafta olduğunda, koridorun diğer tarafında fazladan 5 ayak izini "serbest bırakır", böylece aynı anda 5 çocuk daha odada oynayabilir.

Aynı zamanda SemaphoreSlim'in aynı "tuzaklarına" sahiptir ...

Bir çocuk oyunu bitirir ve ayakkabıları toplamadan odayı terk ederse ("bırakmayı" tetiklemezse) teorik olarak boş bir yuva olsa bile yuva tıkalı kalır. Çocuğa genellikle azarlanır.

Bazen bir veya iki sinsi çocuk ayakkabılarını başka bir yere gizler ve tüm ayak izleri alınmış olsa bile odaya girer (yani, SemaphoreSlim odada kaç çocuğun olduğunu "gerçekten" kontrol etmez).

Odanın aşırı kalabalık olması çocukların ağlaması ve öğretmen odayı tamamen kapatmasıyla sonuçlandığından, bu genellikle iyi bitmez.


9
Bu tür cevaplar favorilerim.
My Stack Overfloweth

7

Bu sorunun gerçekten bir geri sayım kilitleme senaryosuyla ilgili olduğunu kabul etsem de, SemaphoreSlim'i basit bir asenkron kilit olarak kullanmak isteyenler için keşfettiğim bu bağlantıyı paylaşmaya değer olduğunu düşündüm. Kodlamayı daha temiz ve daha güvenli hale getirebilecek using ifadesini kullanmanıza olanak tanır.

http://www.tomdupont.net/2016/03/how-to-release-semaphore-with-using.html

Ben takas yaptım _isDisposed=trueve _semaphore.Release()durumda, her nasılsa birden çok kez çağrıldı olsa kendi atarken etrafında.

Ayrıca SemaphoreSlim'in bir evresel kilit olmadığına dikkat etmek önemlidir, yani aynı iş parçacığı WaitAsync'i birden çok kez çağırırsa, semaforun sahip olduğu sayı her seferinde azalır. Kısacası SemaphoreSlim, Thread farkında değildir.

Kod kalitesiyle ilgili sorularla ilgili olarak, her zaman piyasaya sürülmesini sağlamak için Sürümü bir deneme sonunda koymak daha iyidir.


6
Bağlantılar zamanla ölme eğiliminde olduğundan ve bu da yanıtı değersiz kıldığından, yalnızca bağlantı içeren yanıtlar göndermek tavsiye edilmez. Mümkünse, en iyisi cevabınızda kilit noktaları veya anahtar kod bloğunu özetlemektir.
John
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.