2016-04-14 11 views
6

(i5 aile) SemaphoreSlim kıyasla benim kod performans farkı iseC# SpinWait Bu kod sıfır CPU yakın tüketir

public void SpinWait() { 

     for (int i = 0; i < 10000; i++) 
     { 
      Task.Factory.StartNew(() => 
      { 
       var sw = new SpinWait(); 
       while (true) 
       { 
        sw.SpinOnce(); 
       } 
      }); 
     } 
    } 

(zaman iplik gerçekten haklı 5 vaka için 3x kere veya daha fazla olduğu Mops). Ancak, uzun süreli bekleme için kullanmaktan endişe duyuyorum. Standart tavsiye iki fazlı bekleme işlemini uygulamaktır. NextSpinWillYield özelliğini kontrol edebilir ve varsayılan eğirme yinelemelerini vermeksizin bir sayaç + sıfırlama yapabilir ve bir semafor için geri dönüş yapabilirim.

Ancak uzun vadede beklemek için sadece SpinWait.SpinOnce kullanmanın olumsuzlukları nelerdir? implementation'u inceledim ve gerektiğinde uygun şekilde verdim. Modern CPU'larda PAUSE komutunu kullanan ve Intel'a göre oldukça verimli olan Thread.SpinWait kullanır.

Görev Yöneticisi'nin izlenmesinde bulduğum bir sorun, varsayılan ThreadPool algoritması nedeniyle kademeli olarak artması durumunda iş parçacıklarının sayısıdır (tüm görevler meşgul olduğunda her saniye bir iş parçacığı ekler). Bu, ThreadPool.SetMaxThreads kullanılarak çözülebilir ve daha sonra iş parçacığı sayısı sabittir ve CPU kullanımı hala sıfıra yakındır.

Uzun süre bekletilen görevlerin sayısı sınırlanırsa, uzun süre beklemek için SpinWait.SpinOnce'u kullanmanın diğer tuzakları nelerdir? CPU ailesi, işletim sistemi, .NET sürümüne bağlı mı?

(Sadece netleştirmek için: Hala Sadece nedenini SpinOnce her zaman kullanmıyor curios değilim, iki fazlı bekleyen uygulayacak)

cevap

9

Peki, aşağı tarafı, gördüğünüz bir tam da senin kod hiçbir şey yapmadan bir iş parçacığı işgal ediyor. Diğer kodların çalışmasını engellemek ve threadpool yöneticisini bu konuda bir şeyler yapmaya zorlamak. ThreadPool.SetMaxThreads() ile tinkering sadece bir kanama yara olması muhtemel bir grup yardımcısı, sadece eve uçak yakalamak gerektiğinde bunu kullanın.

İplik, yalnızca bir iş parçacığı içerik anahtarından daha verimli olduğundan çok iyi bir garantiye sahip olduğunuzda denenmelidir. Bunun anlamı, iş parçacığının 10.000 işlemci döngüsünde veya daha az süre içinde devam edebileceğinden emin olmanız gerektiği anlamına gelir. Bu sadece 5 mikrosaniye, çoğu programcının "uzun vadeli" olarak gördüklerinden daha az bir bütünlük vermez.

Bunun yerine iş parçacığı içerik anahtarını tetikleyen bir eşitleme nesnesi kullanın. Ya da lock anahtar kelimesi.

İşlemciye yalnızca diğer bekleyen iş parçacıkları işlerini yapabilmeleri için değil, çok daha fazla iş başarmakla kalmaz, aynı zamanda işletim sistemi iş parçacığı zamanlayıcısı için mükemmel bir işaret sağlar. İşaret edilen bir senkronizasyon nesnesi, iş parçacığının önceliğini çarpacak ve bu sayede işlemcinin daha sonra gelmesi olasıdır.

+0

Teşekkürler! BTW, kaç saniye mikrosaniyenin iplik uyandırmasını alır, örn. Eğer semaphore.WaitAsync (-1, jeton) 'da beklersam? Eğer spinwait ve 'SpinOne' verimleri' Sleep (1) 'ile yapılırsa, en kötü durumda' Sleep (1) 'dedikten sonra tam olarak bir sinyalin gelmesi durumunda en az 15 msn gecikmeyle karşılaşıyorum. Bunun yerine bir semaforya geçersem, semaphore.Release() 'den sonra uyanan bir iş parçacığının en kötü gecikmesi nedir? –

+0

Makine üzerinde neler olup bittiğine bağlı. Ayrıca diğer süreçlerin ve tabii ki çekirdek konuların sahip olduğu iş parçacıkları ile rekabet etmek zorundasınız. Milisaniye değil, mikrosaniye alır. Sadece Kronometre ile ölçün, ara sıra en kötü durum oldukça uzun olabileceğinden, birçok ölçümün medyanını aldığınızdan emin olun. Ve bunun hakkında yapabileceğiniz bir şey olmadığını aklınızdan çıkarmayın, bu yüzden sadece bilgilendirme amaçlıdır. Asla Sleep() kullanmayın. –

+0

Semaforun serbest bırakılmasının ardından .NET ile hiçbir ilgisi yok ve C/C++ veya hatta montaj bile işe yaramayacak mı? (sadece bu donanım/işletim sistemi tasarımı olduğunu anlamak için kullanmayın) –