Yüksek trafik senaryosunda ThreadPool.QueueUserWorkItem'i ASP.NET'te kullanma


111

Her zaman kısa ömürlü arka plan görevleri için (kritik olmayan diyelim) ThreadPool'u kullanmanın ASP.NET'te bile en iyi uygulama olarak görüldüğü izlenimine kapılmıştım, ancak daha sonra aksini öneren bu makaleye rastladım - argüman, ASP.NET ile ilgili isteklerle ilgilenmek için ThreadPool'u bırakmanız gerektiğidir.

İşte şimdiye kadar küçük eşzamansız görevleri şu şekilde yapıyorum:

ThreadPool.QueueUserWorkItem(s => PostLog(logEvent))

Ve makale bunun yerine, aşağıdakine benzer şekilde açıkça bir iş parçacığı oluşturmayı öneriyor:

new Thread(() => PostLog(logEvent)){ IsBackground = true }.Start()

İlk yöntemin yönetilme ve sınırlandırılma avantajı vardır, ancak arka plan görevlerinin ASP.NET istek işleyicileriyle iş parçacıkları için rekabet etme olasılığı (makale doğruysa) vardır. İkinci yöntem, ThreadPool'u serbest bırakır, ancak sınırsız olma ve dolayısıyla potansiyel olarak çok fazla kaynak kullanma pahasına.

Yani sorum şu, makaledeki tavsiye doğru mu?

Siteniz ThreadPool'unuz dolacak kadar çok trafik alıyorsa, bant dışına çıkmak daha mı iyidir yoksa tam bir ThreadPool, kaynaklarınızın sınırına zaten ulaştığınızı mı ima eder? kendi konularınızı başlatmaya çalışmanız gerekmez mi?

Açıklama: Sadece küçük, kritik olmayan eşzamansız görevler (örneğin, uzaktan günlük kaydı) kapsamında soruyorum, ayrı bir süreç gerektiren pahalı iş öğeleri değil (bu durumlarda daha sağlam bir çözüme ihtiyacınız olacağını kabul ediyorum).


Konu yoğunlaşıyor - tam olarak çözemediğim bu makaleyi ( blogs.msdn.com/nicd/archive/2007/04/16/… ) buldum . Bir yandan, IIS 6.0+ hep parçacığı havuzu çalışan iş parçacığı üzerinde isteklerini (ve önceki sürümleri bu işler söyleyerek gibi görünüyor olabilir yeni .NET 2.0 zaman uyumsuz sayfalarını kullanıyor Ancak eğer"(: Bunu yapmak), ancak daha sonra bu var Async = "true") veya ThreadPool.QueueUserWorkItem (), ardından işlemin zaman uyumsuz kısmı [bir tamamlama portu iş parçacığı] içinde yapılacaktır. " İşlemin eşzamansız kısmı mı?
Jeff Sternal

Başka bir şey - bu, iş parçacığı havuzunun kullanılabilir çalışan iş parçacığının maksimum çalışan iş parçacığından daha düşük olup olmadığını inceleyerek ve ardından aynı işlemi kuyrukta yaparak bir IIS 6.0+ yüklemesinde (şu anda sahip olmadığım) test etmek için yeterince kolay olmalıdır. iş öğeleri.
Jeff Sternal

Yanıtlar:


104

Buradaki diğer cevaplar en önemli noktayı dışarıda bırakıyor gibi görünüyor:

Düşük yüklü bir sitede daha hızlı halletmek için CPU yoğun bir işlemi paralelleştirmeye çalışmadığınız sürece, bir işçi iş parçacığı kullanmanın hiçbir anlamı yoktur.

Bu, hem tarafından oluşturulan ücretsiz iş parçacıkları hem de isteklere yanıt veren new Thread(...)çalışan iş parçacıkları ThreadPooliçin geçerlidir QueueUserWorkItem.

Evet, doğru, çok fazla iş öğesini kuyruğa alarak bir ASP.NET sürecini aç bırakabilirsinizThreadPool . ASP.NET'in başka istekleri işlemesini engelleyecektir. Makaledeki bilgiler bu bakımdan doğrudur; için kullanılan aynı iş parçacığı havuzu QueueUserWorkItem, isteklere hizmet etmek için de kullanılır.

Ancak, bu açlığa neden olacak kadar iş öğesini gerçekten sıraya koyuyorsanız, iş parçacığı havuzunu aç bırakmalısınız ! Kelimenin tam anlamıyla yüzlerce CPU yoğun işlemi aynı anda çalıştırıyorsanız, makine zaten aşırı yüklendiğinde bir ASP.NET isteğine hizmet edecek başka bir çalışan iş parçacığına sahip olmanın ne faydası olur? Bu durumla karşılaşırsanız, tamamen yeniden tasarlamanız gerekir!

Çoğu zaman çok iş parçacıklı kodun ASP.NET'te uygunsuz bir şekilde kullanıldığını görüyorum veya duyuyorum, bu CPU yoğun çalışmayı kuyruğa almak için değil. G / Ç bağlantılı işi sıraya koymak için. Ve G / Ç çalışması yapmak istiyorsanız, bir G / Ç iş parçacığı (G / Ç Tamamlama Bağlantı Noktası) kullanmalısınız.

Özellikle, kullandığınız kütüphane sınıfı tarafından desteklenen zaman uyumsuz geri aramaları kullanıyor olmalısınız. Bu yöntemler her zaman çok açık bir şekilde etiketlenmiştir; onlar sözlerle başlar Beginve End. Olduğu gibi Stream.BeginRead, Socket.BeginConnect, WebRequest.BeginGetResponse, vb.

Bu yöntemler yapmak kullanmak ThreadPool, ancak do IOCPs kullanmak değil ASP.NET istekleri ile müdahale. G / Ç sisteminden gelen bir kesinti sinyaliyle "uyandırılabilen" özel bir hafif iplik türüdür. Ve bir ASP.NET uygulamasında, normalde her çalışan iş parçacığı için bir G / Ç iş parçacığına sahip olursunuz, bu nedenle her bir istekte sıraya alınmış bir zaman uyumsuz işlem olabilir. Bu, herhangi bir önemli performans düşüşü olmaksızın kelimenin tam anlamıyla yüzlerce eşzamansız işlemdir (G / Ç alt sisteminin devam edebileceğini varsayarsak). İhtiyacınız olandan çok daha fazla.

Eşzamansız delegelerin bu şekilde çalışmadığını unutmayın - tıpkı bir işçi iş parçacığı kullanacaklar ThreadPool.QueueUserWorkItem. Bunu yapabilen yalnızca .NET Framework kitaplık sınıflarının yerleşik zaman uyumsuz yöntemleridir. Bunu kendiniz yapabilirsiniz, ancak bu karmaşık ve biraz tehlikelidir ve muhtemelen bu tartışmanın kapsamı dışındadır.

Kanımca bu sorunun en iyi yanıtı ASP.NET'te veya arka plan örneğini kullanmamaktırThreadPool Thread . Bu, bir Windows Forms uygulamasında, kullanıcı arayüzünü duyarlı tutmak için yaptığınız ve ne kadar verimli olduğunu umursamadığınız bir iş parçacığı açmak gibi değil. ASP.NET'te, endişeniz aktarım hızıdır ve tüm bu çalışan iş parçacıkları üzerindeki tüm bu bağlam geçişleri, .NET Framework'ü kullansanız da kullanmasanız da aktarım hızınızı kesinlikle öldürecektirThreadPool .

Lütfen, kendinizi ASP.NET'te iş parçacığı kodu yazarken bulursanız - önceden var olan eşzamansız yöntemleri kullanmak için yeniden yazılıp yazılamayacağını düşünün ve yapamazsa, lütfen koda gerçekten, gerçekten ihtiyacınız olup olmadığını düşünün bir arka plan iş parçacığında çalıştırmak için. Çoğu durumda, muhtemelen net bir fayda sağlamadan karmaşıklık katacaksınız.


Bu ayrıntılı yanıt için teşekkürler ve haklısınız, mümkün olduğunda zaman uyumsuz yöntemleri deniyorum ve kullanıyorum (ASP.NET MVC'deki zaman uyumsuz denetleyicilerle birlikte). Benim örneğimde, uzaktan kaydedici ile, tam olarak yapabileceğim şey bu. Bu ilginç bir tasarım problemi olsa da, eşzamansız işlemeyi, örneğin denetleyici düzeyinden (ikinci durumda) karar vermek yerine kodunuzun en düşük düzeyine (yani, günlükçü uygulamasına) ittiği için , örneğin, seçim yapabilmek için iki kaydedici uygulamasına ihtiyacınız vardır).
Michael Hart

@Michael: Eşzamansız geri aramaları, daha fazla seviyeye çıkarmak istiyorsanız, genellikle oldukça kolaydır; zaman uyumsuz yöntemlerin etrafında bir cephe oluşturabilir ve bunları Action<T>örneğin bir geri arama olarak kullanan tek bir yöntemle sarmalayabilirsiniz . Bir işçi iş parçacığı veya G / Ç iş parçacığı kullanma seçiminin en düşük düzeyde olduğunu kastediyorsanız, bu kasıtlıdır; bir IOCP'ye ihtiyacı olup olmadığına yalnızca bu seviye karar verebilir.
Aaronaught

Bununla birlikte, ilgi çekici bir nokta olarak, ThreadPoolsizi bu şekilde sınırlandıran yalnızca .NET'dir , çünkü muhtemelen geliştiricilerin bunu doğru yapacağına güvenmediler. Yönetilmeyen Windows İş Parçacığı Havuzu çok benzer bir API'ye sahiptir, ancak iş parçacığı türünü seçmenize izin verir.
Aaronaught

2
G / Ç Tamamlama Bağlantı Noktaları (IOCP). IOCP'nin tanımı tam olarak doğru değil. IOCP'de, bekleyen TÜM görevler üzerinde sırayla çalışan statik sayıda çalışan iş parçacığına sahipsiniz. boyut olarak sabit veya dinamik olabilen iş parçacığı havuzlarıyla karıştırılmamalıdır AMA her görev için bir iş parçacığı vardır - korkunç bir şekilde ölçeklenir. ASYNC'in aksine, görev başına bir iş parçacığına sahip değilsiniz. bir IOCP iş parçacığı görev 1'de biraz çalışabilir, ardından görev 3'e, görev 2'ye geçebilir ve sonra tekrar görev 1'e dönebilir. görev oturumu durumları kaydedilir ve iş parçacıkları arasında aktarılır.
MickyD

1
Veritabanı ekleri ne olacak? ASYNC SQL komutu var mı (Yürütme gibi)? Veritabanı eklemeleri, etrafındaki en yavaş G / Ç işlemi ile ilgilidir (kilitlenme nedeniyle) ve ana iş parçacığının satır (lar) ın eklenmesini beklemesi sadece CPU döngülerinin boşa harcanmasıdır.
Ian Thompson

45

Microsoft'taki ASP.NET ekibinden Thomas Marquadt'a göre, ASP.NET ThreadPool'u (QueueUserWorkItem) kullanmak güvenlidir.

Makaleden :

S) ASP.NET Uygulamam CLR ThreadPool iş parçacıklarını kullanıyorsa, istekleri yürütmek için CLR ThreadPool'u da kullanan ASP.NET'i aç bırakmaz mıyım? ..

A) Özetlemek gerekirse, ASP.NET'in iş parçacığını aç bırakma konusunda endişelenmeyin ve burada bir sorun olduğunu düşünüyorsanız bana bildirin, biz de halledelim.

S) Kendi konu başlıklarımı (yeni Konu) oluşturmalı mıyım? CLR ThreadPool'u kullandığı için ASP.NET için bu daha iyi olmayacak.

A) Lütfen yapma. Ya da başka bir deyişle, hayır !!! Gerçekten zekiyseniz - benden çok daha zekiyseniz - o zaman kendi konularınızı oluşturabilirsiniz; aksi takdirde aklınızdan bile geçirmeyin. Sık sık yeni ileti dizileri oluşturmamanız için bazı nedenler şunlardır:

  1. QueueUserWorkItem'e kıyasla çok pahalı ... Bu arada, CLR'lerden daha iyi bir ThreadPool yazabilirseniz, sizi Microsoft'ta bir işe başvurmanızı tavsiye ederim çünkü kesinlikle sizin gibi insanları arıyoruz !.

4

Web siteleri ileti dizileri oluşturmamalı.

Genellikle bu işlevi, daha sonra iletişim kurduğunuz bir Windows Hizmetine taşırsınız (onlarla konuşmak için MSMQ kullanıyorum).

-- Düzenle

Burada bir uygulamayı anlattım: ASP.NET MVC Web Uygulamasında Sıraya Dayalı Arka Plan İşleme

-- Düzenle

Bunun neden dizilerden daha iyi olduğunu genişletmek için:

MSMQ kullanarak başka bir sunucu ile iletişim kurabilirsiniz. Makineler arasında bir kuyruğa yazabilirsiniz, bu nedenle, herhangi bir nedenle, arka plan görevinizin ana sunucunun kaynaklarını çok fazla kullandığını belirlerseniz, bunu oldukça önemsiz bir şekilde değiştirebilirsiniz.

Ayrıca, yapmaya çalıştığınız görevi toplu işlemenize de olanak tanır (e-posta gönderin / ne olursa olsun).


4
Bu genel ifadenin her zaman doğru olduğu konusunda hemfikir değilim - özellikle kritik olmayan görevler için. Sadece eşzamansız günlük kaydı amacıyla bir Windows Hizmeti oluşturmak kesinlikle aşırı gözüküyor. Ayrıca, bu seçenek her zaman mevcut değildir (MSMQ ve / veya bir Windows Hizmetinin dağıtılabilmesi).
Michael Hart

Elbette, ancak bu, bir web sitesinden eşzamansız görevleri gerçekleştirmenin 'standart' yoludur (diğer bazı işlemlere karşı kuyruk teması).
Noon Silk

2
Zaman uyumsuz görevlerin tümü eşit şekilde oluşturulmaz, bu nedenle örneğin ASP.NET'te zaman uyumsuz sayfalar bulunur. Uzak bir web hizmetinden görüntülemek için bir sonuç almak istersem, bunu MSMQ aracılığıyla yapmayacağım. Bu durumda, uzak bir gönderi kullanarak bir günlüğe yazıyorum. Bir Windows Hizmeti yazmak veya bunun için MSMQ'yu bağlamak soruna uymuyor (ve bu belirli uygulama Azure'da olduğu için ben de yapamam).
Michael Hart

1
Şunu düşünün: uzak bir ana bilgisayara mı yazıyorsunuz? Ya bu ana bilgisayar çalışmıyorsa veya ulaşılamıyorsa? Yazınızı yeniden denemek ister misiniz? Belki yapacaksın, belki yapmayacaksın. Uygulamanızla yeniden denemek zor. Servis ile oldukça önemsiz hale geliyor. Bunu yapamayabileceğinizi anlıyorum ve başka birinin web sitelerinden ileti dizileri oluşturmayla ilgili belirli sorunlara yanıt vermesine izin vereceğim [ör. İleti dizinizin arka planı yoksa vb.], Ancak "doğru" nun ana hatlarını çiziyorum bunu yapmanın yolu. Azure'a aşina değilim, ancak ec2 kullanmış olsam da (bunun üzerine bir işletim sistemi yükleyebilirsiniz, böylece her şey yolunda gider).
Noon Silk

@silky, yorumlarınız için teşekkürler. Bu daha ağır (ancak dayanıklı) çözümden kaçınmak için "kritik değil" demiştim. Sıraya alınmış iş öğeleri etrafında en iyi uygulamayı istemediğim için soruyu açıklığa kavuşturdum. Azure bu tür senaryoyu destekler (kendi kuyruk depolama alanına sahiptir) - ancak kuyruklama işlemi senkronize günlük kaydı için çok pahalıdır, bu nedenle yine de senkronize olmayan bir çözüme ihtiyacım var. Benim durumumda, başarısızlığın tuzaklarının farkındayım, ancak bu belirli günlük kaydı sağlayıcısının başarısız olması durumunda daha fazla altyapı eklemeyeceğim - başka günlük sağlayıcılarım da var.
Michael Hart

4

ASP.NET'te hızlı, düşük öncelikli zaman uyumsuz çalışma için genel uygulamanın, kaynaklarınızın sınırlandırılmasını istediğiniz gibi özellikle yüksek trafik senaryoları için .NET iş parçacığı havuzunu kullanmak olacağını kesinlikle düşünüyorum.

Ayrıca, iş parçacığının uygulanması gizlidir - kendi iş parçacıklarınızı oluşturmaya başlarsanız, onları da doğru bir şekilde yönetmeniz gerekir. Yapamayacağını söylemiyorum ama neden o tekerleği yeniden icat ettin?

Performans bir sorun haline gelirse ve iş parçacığı havuzunun sınırlayıcı faktör olduğunu belirleyebilirseniz (veritabanı bağlantıları, giden ağ bağlantıları, bellek, sayfa zaman aşımları vb. Değil), daha fazla çalışan iş parçacığına, daha yüksek kuyruğa alınmış isteklere izin vermek için iş parçacığı havuzu yapılandırmasını değiştirirsiniz. , vb.

Performans sorununuz yoksa, ASP.NET istek kuyruğuyla çekişmeyi azaltmak için yeni iş parçacıkları oluşturmayı seçmek klasik erken optimizasyondur.

İdeal olarak, bir günlük kaydı işlemi yapmak için ayrı bir iş parçacığı kullanmanıza gerek kalmaz - yalnızca orijinal iş parçacığının işlemi olabildiğince hızlı tamamlamasını etkinleştirin, burada MSMQ ve ayrı bir tüketici iş parçacığı / süreci resme gelir. Bunun daha ağır ve uygulanacak daha fazla iş olduğunu kabul ediyorum, ancak burada gerçekten dayanıklılığa ihtiyacınız var - paylaşılan, bellek içi bir sıranın değişkenliği, hoş karşılanmasını çabucak yıpratacaktır.


2

QueueUserWorkItem'i kullanmalı ve vebadan kaçınacağınız gibi yeni iş parçacıkları oluşturmaktan kaçınmalısınız. Aynı ThreadPool'u kullandığı için ASP.NET'i neden aç bırakmayacağınızı açıklayan bir görsel için, çok yetenekli bir hokkabazın yarım düzine bowling lobutunu, kılıcı veya uçmakta olan her şeyi tutmak için iki elini kullandığını hayal edin. Kendi iş parçacığınızı oluşturmanın neden kötü olduğuna dair bir görsel için, Seattle'da yoğun bir şekilde otoyola giriş rampaları kullanıldığında, araçların ışık kullanmak yerine hemen trafiğe girmesine izin verdiğini ve giriş sayısını birkaç saniyede bir ile sınırlandırdığını düşünün. . Son olarak, ayrıntılı bir açıklama için lütfen şu bağlantıya bakın:

http://blogs.msdn.com/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx

Teşekkürler, Thomas


Bu bağlantı çok yararlı, bunun için teşekkürler Thomas. @ Aaronaught'ın yanıtı hakkında ne düşündüğünüzü de duymak isterim.
Michael Hart

Aaronaught'a katılıyorum ve aynısını blog yazımda da söyledim. Şöyle söylüyorum, "Bu kararı basitleştirme girişiminde, başka türlü hiçbir şey yapmazken ASP.NET istek iş parçacığını engelleyecekseniz, yalnızca [başka bir iş parçacığına] geçmelisiniz. Bu bir aşırı basitleştirme, ama ben deniyorum kararı basitleştirmek için. " Başka bir deyişle, bunu engellemeyen hesaplama işi için yapmayın, ancak uzak bir sunucuya zaman uyumsuz web hizmeti talepleri yapıyorsanız yapın. Aaronaught'ı dinleyin! :)
Thomas

1

Bu makale doğru değil. ASP.NET, ASP.NET isteklerine hizmet etmek için kendi iş parçacığı havuzuna, yönetilen çalışan iş parçacıklarına sahiptir. Bu havuz genellikle birkaç yüz iş parçacığıdır ve bazı daha küçük işlemci katları olan ThreadPool havuzundan ayrıdır.

ASP.NET'te ThreadPool kullanılması, ASP.NET çalışan iş parçacıklarını etkilemez. ThreadPool kullanmak iyidir.

Aynı zamanda, sadece mesajları günlüğe kaydetmek ve günlük mesajlarını bu iş parçacığına geçirmek için üretici / tüketici modelini kullanmak için tek bir iş parçacığı kurmak da kabul edilebilir. Bu durumda, iş parçacığı uzun ömürlü olduğundan, günlüğü çalıştırmak için tek bir yeni iş parçacığı oluşturmalısınız.

Her mesaj için yeni bir ileti dizisi kullanmak kesinlikle abartılıdır.

Diğer bir alternatif, sadece günlüğe kaydetmekten bahsediyorsanız, log4net gibi bir kitaplık kullanmaktır. Günlük kaydını ayrı bir iş parçacığında ele alır ve bu senaryoda ortaya çıkabilecek tüm bağlam sorunlarıyla ilgilenir.


1
@Sam, aslında log4net kullanıyorum ve günlüklerin ayrı bir iş parçacığına yazıldığını görmüyorum - etkinleştirmem gereken bir tür seçenek var mı?
Michael Hart

1

Makalenin yanlış olduğunu söyleyebilirim. Eğer güvenle (ayrı uygulama havuzları kullanarak) birden çok uygulama ve birden çok web sitesinde havuzu kullanabilirsiniz geniş .NET dükkanı çalıştırıyorsanız, basitçe bir açıklamada dayalı ThreadPool'da belgelerinde:

İşlem başına bir iş parçacığı havuzu vardır. İş parçacığı havuzunun varsayılan boyutu, kullanılabilir işlemci başına 250 çalışan iş parçacığı ve 1000 G / Ç tamamlama iş parçacığıdır. İş parçacığı havuzundaki iş parçacığı sayısı SetMaxThreads yöntemi kullanılarak değiştirilebilir. Her iş parçacığı varsayılan yığın boyutunu kullanır ve varsayılan öncelikte çalışır.


Tek bir işlemde çalışan bir uygulama, kendisini tamamen çökertebilir! (Ya da en azından kendi performansını, iş parçacığı havuzunu kaybeden bir teklif haline getirecek kadar düşürmek.)
Jeff Sternal

Öyleyse ASP.NET isteklerinin G / Ç tamamlama iş parçacıklarını kullandığını tahmin ediyorum (çalışan iş parçacıklarının aksine) - bu doğru mu?
Michael Hart

Fritz Onion'un makalesinden cevabıma bağlandım: "Bu paradigma ASP.NET'te isteklerin işlenme şeklini [IIS 5.0'dan IIS 6.0'a] değiştiriyor. İstekleri inetinfo.exe'den ASP.NET çalışan işlemine göndermek yerine http. sys, her bir isteği doğrudan uygun süreçte sıraya koyar. Böylece tüm istekler, artık CLR iş parçacığı havuzundan ve hiçbir zaman G / Ç iş parçacıklarından çekilen çalışan evreler tarafından karşılanır . " (vurgu)
Jeff Sternal

Hmmm, hala tam olarak emin değilim ... Bu makale Haziran 2003'ten. Bunu Mayıs 2004'ten okursanız (kuşkusuz hala oldukça eski), "Sleep.aspx test sayfası bir ASP'yi saklamak için kullanılabilir .NET G / Ç iş parçacığı meşgul ", burada Sleep.aspx yalnızca geçerli yürütme iş parçacığının uykuya geçmesine neden olur: msdn.microsoft.com/en-us/library/ms979194.aspx - Bir şansım olduğunda göreceğim Bu örneği kodlayabilir ve IIS 7 ve .NET 3.5 üzerinde test edebilirsem
Michael Hart

Evet, o paragrafın metni kafa karıştırıcı. Bu bölümün ilerisinde, işleri açıklığa kavuşturan bir destek konusuna ( support.microsoft.com/default.aspx?scid=kb;EN-US;816829 ) bağlanır: G / Ç tamamlama iş parçacıklarında istek çalıştırmak bir .NET Framework 1.0'dı. ASP.NET 1.1 Haziran 2003 Düzeltme Toplama Paketi'nde düzeltilen sorun (bundan sonra "TÜM istekler artık İş parçacıkları üzerinde çalışıyor"). Daha da önemlisi, bu örnek, ASP.NET iş parçacığı havuzunun, .NET Framework tarafından sunulan aynı iş parçacığı havuzu olduğunu açıkça göstermektedir System.Threading.ThreadPool.
Jeff Sternal

1

Geçen hafta işte benzer bir soru sordum ve size aynı cevabı vereceğim. Neden istek başına çok iş parçacıklı web uygulamaları yapıyorsunuz? Bir web sunucusu, birçok isteği zamanında sağlamak için (yani çoklu iş parçacığı) yoğun bir şekilde optimize edilmiş harika bir sistemdir. Web'deki hemen hemen her sayfayı talep ettiğinizde ne olacağını düşünün.

  1. Bir sayfa için istek yapıldı
  2. Html geri sunulur
  3. Html, istemciye daha fazla istek (js, css, resimler vb.)
  4. Daha fazla bilgi geri verilir

Uzaktan günlüğe kaydetme örneğini veriyorsunuz, ancak bu, kaydediciniz için bir endişe kaynağı olmalıdır. Mesajları zamanında almak için eşzamansız bir süreç yürürlükte olmalıdır. Hatta Sam, kaydedicinizin (log4net) bunu zaten desteklemesi gerektiğine işaret ediyor.

Sam, CLR üzerinde İş Parçacığı Havuzu kullanmanın IIS'deki iş parçacığı havuzunda sorunlara neden olmayacağı konusunda da haklıdır. Burada ilgilenilmesi gereken şey, bir süreçten iş parçacığı üretmediğiniz, IIS iş parçacığı dizilerinden yeni iş parçacıkları üretmenizdir. Bir fark var ve ayrım önemli.

İş Parçacığı ve İşlem

Hem iş parçacıkları hem de işlemler bir uygulamayı paralelleştirme yöntemleridir. Bununla birlikte, süreçler, kendi durum bilgilerini içeren, kendi adres alanlarını kullanan ve yalnızca birbirleriyle işlemler arası iletişim mekanizmaları aracılığıyla etkileşime giren (genellikle işletim sistemi tarafından yönetilen) bağımsız yürütme birimleridir. Uygulamalar tipik olarak tasarım aşamasında süreçlere bölünür ve bir ana süreç, önemli uygulama işlevselliğini mantıksal olarak ayırmak mantıklı olduğunda açıkça alt süreçleri ortaya çıkarır. Diğer bir deyişle süreçler mimari bir kurgudur.

Aksine, bir iş parçacığı, bir uygulamanın mimarisini etkilemeyen bir kodlama yapısıdır. Tek bir süreç birden çok iş parçacığı içerebilir; bir süreç içindeki tüm iş parçacıkları aynı durumu ve aynı bellek alanını paylaşır ve aynı değişkenleri paylaştıkları için birbirleriyle doğrudan iletişim kurabilirler.

Kaynak


3
@Ty, girdiniz için teşekkürler, ancak bir web sunucusunun nasıl çalıştığının farkındayım ve soruyla gerçekten alakalı değil - yine, soruda söylediğim gibi, bu konuda mimari olarak rehberlik istemiyorum konu. Spesifik teknik bilgi istiyorum. Halihazırda bir eşzamansız sürecin yerinde olması gereken "kaydedicinin endişesi" olduğuna gelince - eşzamansız işlemin kaydedici uygulaması tarafından nasıl yazılması gerektiğini düşünüyorsunuz?
Michael Hart

0

Başvurulan makaleye (C # feeds.com) katılmıyorum. Yeni bir ileti dizisi oluşturmak kolay ama tehlikelidir. Tek bir çekirdekte çalışacak en uygun aktif iş parçacığı sayısı aslında şaşırtıcı derecede düşüktür - 10'dan azdır. İş parçacıkları küçük görevler için oluşturulmuşsa, makinenin iş parçacıkları arasında geçiş yapmak için zaman harcamasına neden olmak çok kolaydır. Dişler, yönetimi GEREKTİREN bir kaynaktır. WorkItem soyutlaması bunun üstesinden gelmek için var.

Burada, istekler için mevcut olan iş parçacığı sayısını azaltmak ile herhangi birinin verimli bir şekilde işlenmesine izin vermek için çok fazla iş parçacığı oluşturmak arasında bir denge vardır. Bu çok dinamik bir durum ama bence iş parçacığının yaratılmasının önünde kalmak için onu işlemciye bırakmak yerine aktif olarak yönetilmesi (bu durumda iş parçacığı havuzu tarafından).

Son olarak makale, ThreadPool'u kullanmanın tehlikeleri hakkında oldukça kapsamlı açıklamalar yapıyor, ancak onları desteklemek için gerçekten somut bir şeye ihtiyacı var.


0

IIS'nin gelen istekleri işlemek için aynı ThreadPool'u kullanıp kullanmadığı kesin bir yanıt almak için zor görünüyor ve aynı zamanda sürümler üzerinde değişmiş gibi görünüyor. Bu nedenle, ThreadPool iş parçacıklarını aşırı kullanmamak iyi bir fikir gibi görünebilir, böylece IIS'de bunlardan birçoğu mevcuttur. Öte yandan, her küçük görev için kendi iş parçanızı oluşturmak kötü bir fikir gibi görünüyor. Muhtemelen, günlüğünüzde bir tür kilitlenme vardır, bu nedenle bir seferde yalnızca bir iş parçacığı ilerleyebilir ve geri kalanı sırayla planlanır ve planlanmaz (yeni bir iş parçacığı oluşturmanın ek yükünden bahsetmiyorum bile). Esasen, ThreadPool'un kaçınmak için tasarlandığı problemlerle karşılaşıyorsunuz.

Görünüşe göre uygulamanızın, mesajları iletebileceğiniz tek bir günlük kaydı dizisi tahsis etmesi makul bir uzlaşma olacaktır. Uygulamanızı yavaşlatmamak için mesaj göndermenin olabildiğince hızlı olmasına dikkat etmek istersiniz.


0

Parallel.For veya Parallel.ForEach'i kullanabilir ve sorunsuz çalışması ve havuz açlığını önlemek için ayırmak istediğiniz olası iş parçacıklarının sınırını tanımlayabilirsiniz.

Bununla birlikte, arka planda çalıştırılırken ASP.Net web uygulamasında aşağıdaki saf TPL stilini kullanmanız gerekecektir.

var ts = new CancellationTokenSource();
CancellationToken ct = ts.Token;

ParallelOptions po = new ParallelOptions();
            po.CancellationToken = ts.Token;
            po.MaxDegreeOfParallelism = 6; //limit here

 Task.Factory.StartNew(()=>
                {                        
                  Parallel.ForEach(collectionList, po, (collectionItem) =>
                  {
                     //Code Here PostLog(logEvent);
                  }
                });
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.