ASP.NET MVC zaman uyumsuz işlemleri yapmak .NET 4'te ThreadPool bir iş parçacığı kullanın


158

Bu sorudan sonra, ASP.NET MVC'de zaman uyumsuz işlemler kullanırken rahat etmemi sağlıyor. Bunun üzerine iki blog yazısı yazdım:

ASP.NET MVC'de eşzamansız işlemler hakkında çok fazla yanlış anlama var.

Bu cümleyi her zaman duyuyorum: İşlemler eşzamansız olarak çalışıyorsa uygulama daha iyi ölçeklenebilir

Ben de bu tür cümleler çok duydum: Eğer büyük bir trafik hacminiz varsa, sorgularınızı eşzamansız olarak yerine getirmemek daha iyi olabilir - bir talebe hizmet vermek için 2 ekstra iş parçacığı tüketmek, kaynakları diğer gelen isteklerden uzaklaştırır.

Bence bu iki cümle tutarsız.

Threadpool ASP.NET üzerinde nasıl çalıştığı hakkında çok fazla bilgi yok ama threadpool iş parçacıkları için sınırlı bir boyutu olduğunu biliyorum. Dolayısıyla, ikinci cümlenin bu konuyla ilgili olması gerekir.

Ve ASP.NET MVC zaman uyumsuz işlemleri .NET 4'te ThreadPool bir iş parçacığı kullanıp kullanmadığını bilmek ister misiniz?

Örneğin, bir AsyncController uyguladığımızda uygulama nasıl yapılandırılır? Büyük trafik alırsam, AsyncController'ı uygulamak iyi bir fikir mi?

Dışarıda bu siyah perdeyi gözlerimin önünde alıp ASP.NET MVC 3 (NET 4) üzerindeki eşzamansızlık konusundaki anlaşmayı açıklayabilecek kimse var mı?

Düzenle:

Aşağıdaki belgeyi neredeyse yüzlerce kez okudum ve ana anlaşmayı anlıyorum ama hala karışıklık var çünkü orada çok fazla tutarsız yorum var.

ASP.NET MVC'de Eşzamansız Denetleyici Kullanma

Düzenle:

Diyelim ki aşağıdaki gibi denetleyici eylemim var (bir uygulama değil AsyncController):

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

Burada gördüğünüz gibi bir operasyon başlatıyorum ve unutuyorum. Sonra, tamamlanmasını beklemeden hemen dönüyorum.

Bu durumda, bunun threadpool'dan bir iplik kullanması gerekir mi? Eğer öyleyse, tamamlandıktan sonra, bu konuya ne olur? Mu GCgeliyor ve tamamlar hemen sonra temizlemek?

Düzenle:

@ Darin'in cevabı için, veritabanıyla konuşan async kodu örneği:

public class FooController : AsyncController {

    //EF 4.2 DbContext instance
    MyContext _context = new MyContext();

    public void IndexAsync() { 

        AsyncManager.OutstandingOperations.Increment(3);

        Task<IEnumerable<Foo>>.Factory.StartNew(() => { 

           return 
                _context.Foos;
        }).ContinueWith(t => {

            AsyncManager.Parameters["foos"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });

        Task<IEnumerable<Bars>>.Factory.StartNew(() => { 

           return 
                _context.Bars;
        }).ContinueWith(t => {

            AsyncManager.Parameters["bars"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });

        Task<IEnumerable<FooBar>>.Factory.StartNew(() => { 

           return 
                _context.FooBars;
        }).ContinueWith(t => {

            AsyncManager.Parameters["foobars"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });
    }

    public ViewResult IndexCompleted(
        IEnumerable<Foo> foos, 
        IEnumerable<Bar> bars,
        IEnumerable<FooBar> foobars) {

        //Do the regular stuff and return

    }
}

Cevapta emin değilim, ama asenkron ve çoklu iş parçacığına dikkat çekmeye değer farklı şeyler. Bu nedenle, asenkron işleme ile sabit sayıda ipliğe sahip olmak mümkün olacaktır. Bir sayfa için G / Ç'nin engellenmesi gerektiğinde, başka bir sayfa aynı iş parçacığında çalışma şansı elde edilir. Bu ifadelerin her ikisi de doğru olabilir, zaman uyumsuz işleri daha hızlı yapabilir, ancak çok fazla iş parçacığı bir sorundur.
Chris Chilvers

@ChrisChilvers Evet, asenkron çalıştırmada çoklu kullanım her zaman gerekli değildir. Bunu çoktan anladım, ancak sanırım söyleyebildiğim kadarıyla bunun üzerinde bir denetleyicim yok. AsyncController benim bakış açımdan kaç tane iş parçacığı istediğini döndürüyor ancak bu konuda da emin değil. WPF gibi masaüstü uygulamalarında threadpool kavramı var mı? İş parçacığı sayısının bu tür uygulamalarda bir sorun olmadığını düşünüyorum.
tugberk


Bence sorun (ve dolayısıyla tutarsızlık) ikinci ifade birçok iş parçacığı anlamına geldiğinde asenkron kullanır. Bunun nedeni, asp.net'in zaman uyumsuz sayfaları uygulamasının nedeni olabilir ve bu nedenle belirli uygulama sorunu karıştırmıştır (soruna neden olan özelliğin adı zaman uyumsuz sayfalar olacağından), ancak belirli uygulamadan emin değilim . Yani ya "çok sayıda iş parçacığı" anlamına gelir, ya da gelecekteki sürümler uygulamayı değiştirebileceğinden "asp.net sürüm X içindeki" zaman uyumsuz sayfalar "anlamına gelir. Ya da sadece bir sayfa içinde zaman uyumsuzluğu gerçekleştirmek için iş parçacığı havuzunu kullanmak anlamına gelir.
Chris Chilvers

@ChrisChilvers oh, adamım! Bu yorumlardan sonra kafam karıştı: s
tugberk

Yanıtlar:


177

İşte bir var mükemmel bir makale sana daha iyi (asenkron kontrolörleri temelde temsil budur) ASP.NET zaman uyumsuz işlem anlamak için okuma öneriyoruz.

İlk önce standart bir senkron eylemi düşünelim:

public ActionResult Index()
{
    // some processing
    return View();
}

Bu eylem için bir istek yapıldığında, iş parçacığı havuzundan bir iş parçacığı çizilir ve bu eylemin gövdesi bu iş parçacığında yürütülür. Bu nedenle, bu eylemin içindeki işlem yavaşsa, tüm işlem için bu iş parçacığını engelliyorsunuz demektir, bu nedenle bu iş parçacığı diğer istekleri işlemek için yeniden kullanılamaz. İstek yürütme işleminin sonunda, iş parçacığı iş parçacığı havuzuna döndürülür.

Şimdi asenkron yapıya bir örnek verelim:

public void IndexAsync()
{
    // perform some processing
}

public ActionResult IndexCompleted(object result)
{
    return View();
}

Dizin eylemine bir istek gönderildiğinde, iş parçacığı havuzundan bir iş parçacığı çizilir ve IndexAsyncyöntemin gövdesi yürütülür. Bu yöntemin gövdesi yürütmeyi tamamladığında, iş parçacığı iş parçacığı havuzuna döndürülür. Daha sonra, standardı kullanarak, AsyncManager.OutstandingOperationszaman uyumsuz işlemin tamamlandığını bildirdiğinizde, iş parçacığı havuzundan başka bir iş parçacığı çizilir ve IndexCompletedeylemin gövdesi üzerinde yürütülür ve sonuç istemciye iletilir.

Dolayısıyla, bu modelde görebildiğimiz, tek bir istemci HTTP isteğinin iki farklı iş parçacığı tarafından yürütülebilmesidir.

Şimdi ilginç kısım IndexAsyncyöntemin içinde oluyor . İçinde bir engelleme işlemi varsa, çalışan iş parçacığını engellediğiniz için eşzamansız denetleyicilerin tüm amacını tamamen harcıyorsunuz (bu eylemin gövdesinin iş parçacığı havuzundan çizilen bir iş parçacığında yürütüldüğünü unutmayın).

Peki, sorabileceğiniz asenkron kontrolörlerden ne zaman faydalanabiliriz?

IMHO, G / Ç yoğun işlemleri (uzaktan servislere veritabanı ve ağ çağrıları gibi) olduğunda en fazla kazancı elde edebiliriz. CPU yoğun bir işleminiz varsa, eşzamansız eylemler size çok fazla fayda sağlamaz.

Peki neden G / Ç yoğun işlemlerinden faydalanabiliriz? Çünkü G / Ç Tamamlama Portlarını kullanabiliriz . Tüm işlemin yürütülmesi sırasında sunucuda hiçbir iş parçacığı veya kaynak tüketmediğiniz için IOCP son derece güçlüdür.

Nasıl çalışırlar?

WebClient.DownloadStringAsync yöntemini kullanarak uzak bir web sayfasının içeriğini indirmek istediğimizi varsayalım . İşletim sistemine bir IOCP kaydedip hemen geri dönecek olan bu yöntemi çağırırsınız. Tüm isteğin işlenmesi sırasında sunucunuzda hiçbir iş parçacığı kullanılmaz. Uzak sunucuda her şey olur. Bu çok zaman alabilir, ancak çalışan iş parçacıklarınızı tehlikeye atmadığınız için umursamazsınız. Bir yanıt alındığında IOCP bildirilir, iş parçacığı havuzundan bir iş parçacığı çizilir ve bu iş parçacığında geri arama yürütülür. Ancak gördüğünüz gibi, tüm süreç boyunca hiçbir ipliği tekelleştirmedik.

Aynı şey FileStream.BeginRead, SqlCommand.BeginExecute, ...

Birden çok veritabanı çağrısını paralel hale getirmeye ne dersiniz? 4 engelleme veritabanı çağrısı sırayla gerçekleştirdiğiniz bir eşzamanlı denetleyici eylemi olduğunu varsayalım. Her bir veritabanı çağrısı 200ms alırsa, denetleyici eyleminizin yaklaşık 800ms süreceğini hesaplamak kolaydır.

Bu aramaları sıralı olarak yapmanız gerekmiyorsa, paralel hale getirme performansı artırır mı?

Cevaplanması kolay olmayan büyük soru bu. Belki evet belki hayır. Tamamen bu veritabanı çağrılarını nasıl uyguladığınıza bağlı olacaktır. Daha önce açıklandığı gibi zaman uyumsuz denetleyiciler ve G / Ç Tamamlama Bağlantı Noktaları kullanırsanız, çalışan iş parçacıklarını tekelleştirmeyeceğiniz için bu denetleyici eyleminin ve diğer eylemlerin performansını da artıracaksınız.

Öte yandan, bunları kötü bir şekilde uygularsanız (iş parçacığı havuzundan bir iş parçacığında engellenen bir veritabanı çağrısı ile), temelde bu eylemin toplam yürütme süresini yaklaşık 200 ms'ye düşürürsünüz, ancak 4 işçi iş parçacığını tüketmiş olursunuz. havuzdaki iş parçacıklarının işlenmemesi nedeniyle açlıktan düşebilecek diğer isteklerin performansını düşürmüş olabilir.

Bu yüzden çok zordur ve uygulamanız üzerinde kapsamlı testler yapmaya hazır hissetmiyorsanız, asenkron kontrolörleri uygulamayın, çünkü faydadan daha fazla hasar verebilirsiniz. Bunları yalnızca bunu yapmak için bir nedeniniz varsa uygulayın: örneğin, standart senkron denetleyici eylemlerinin uygulamanız için bir darboğaz olduğunu belirlediniz (kapsamlı yük testleri ve elbette ölçümler yaptıktan sonra).

Şimdi örneğinizi ele alalım:

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

Dizin eylemi için bir istek alındığında, gövdeyi yürütmek için iş parçacığı havuzundan bir iş parçacığı çizilir, ancak gövdesi yalnızca TPL kullanarak yeni bir görev zamanlar . Böylece eylem yürütme sona erer ve iş parçacığı iş parçacığı havuzuna döndürülür. Bunun dışında, TPL işlemlerini gerçekleştirmek için iş parçacığı havuzundan iş parçacıkları kullanır. Bu nedenle, orijinal iş parçacığı iş parçacığı havuzuna döndürülmüş olsa bile, görevin gövdesini yürütmek için bu havuzdan başka bir iş parçacığı çizdiniz. Böylece değerli havuzunuzdan 2 konu tehlikeye soktunuz.

Şimdi aşağıdakileri ele alalım:

public ViewResult Index() { 

    new Thread(() => { 
        //Do an advanced looging here which takes a while
    }).Start();

    return View();
}

Bu durumda el ile bir iplik üretiyoruz. Bu durumda, Dizin eyleminin gövdesinin yürütülmesi biraz daha uzun sürebilir (çünkü yeni bir iş parçacığının oluşturulması mevcut bir havuzdan bir tane çizmekten daha pahalıdır). Ancak, gelişmiş kayıt işleminin yürütülmesi havuzun parçası olmayan bir iş parçacığında yapılacaktır. Bu yüzden, başka bir istekte bulunmak için serbest kalan havuzdaki konuları tehlikeye atmıyoruz.


1
Gerçekten detaylı, teşekkürler! Diyelim ki 4 async Tasks ( System.Threading.Task) IndexAsyncmetodumuz var. Bu işlemler içinde bir sunucuya db çağrıları yapıyoruz. Yani hepsi I / O yoğun operasyonlar, değil mi? Bu durumda, 4 ayrı iş parçacığı mı yaratıyoruz (ya da iş parçacığı havuzundan 4 ayrı iş parçacığı mı alıyoruz)? Çok çekirdekli bir makinem olduğunu varsayarsak, paralel olarak da çalışacaklar, değil mi?
tugberk

10
@tugberk, veritabanı çağrıları G / Ç işlemidir, ancak bunların tümü bunları nasıl uyguladığınıza bağlıdır. Eğer bir engelleme çağrısı olduğu SqlCommand.ExecuteReaderiçin her şeyi boşa harcamak gibi bir engelleme veritabanı çağrısı kullanırsanız . Bu çağrının yürüttüğü iş parçacığını engelliyorsunuz ve bu iş parçacığı havuzdan bir iş parçacığı haline gelirse çok kötü. Eğer Ç tamamlama Limanları / I kullanırsanız, sadece yararlanacaktır: SqlCommand.BeginExecuteReader. Ne yaparsanız yapın IOCP kullanmazsanız, uygulamanızın genel performansından daha fazla zarar vereceğiniz için zaman uyumsuz denetleyiciler kullanmayın.
Darin Dimitrov

1
Çoğu zaman önce EF kodunu kullanıyorum. Uyup uymadığından emin değilim. Genelde ne yaptığımı gösteren bir örnek koydum. Soruyu güncelledim, bir göz atabilir misin?
tugberk

3
@tugberk, bunları paralel olarak çalıştırıyorsunuz, bu nedenle toplam yürütme süresi, bunları sırayla çalıştırdığınızdan daha az. Ancak bunları çalıştırmak için işçi iş parçacıklarını kullanırsınız. Aslında EF tembeldir, bu yüzden yaptığınız zaman _context.Foohiçbir şey yapmazsınız. Sadece bir ifade ağacı inşa ediyorsun. Buna çok dikkat edin. Sorgu yürütme, yalnızca sonuç kümesi üzerinde numaralandırmaya başladığınızda ertelenir. Ve bu görüşte gerçekleşirse, bu performans için felaket olabilir. Bir EF sorgusunu hevesle yürütmek .ToList()için sonuna ekleyin .
Darin Dimitrov

2
@tugberk, ağır yük altında nasıl davrandığını görmek için web sitenizde birden çok kullanıcıyı paralel olarak simüle etmek için bir yük test aracına ihtiyacınız olacaktır. Mini Profiler web sitenizdeki yükü simüle edemez. ADO.NET sorgularınızı görmenize ve optimize etmenize ve tek bir isteğin profilini oluşturmanıza yardımcı olabilir, bu da sitenizin çok sayıda kullanıcı tarafından vurulduğunda gerçek dünya durumunda nasıl davrandığını görmeniz gerektiğinde işe yaramaz.
Darin Dimitrov

49

Evet - tüm iş parçacıkları iş parçacığı havuzundan gelir. MVC uygulamanız zaten çok iş parçacıklıdır, bir istek geldiğinde havuzdan yeni bir iş parçacığı alınır ve isteğe hizmet vermek için kullanılır. Bu iş parçacığı, istek tamamen yerine getirilip tamamlanıncaya kadar (diğer isteklerden) 'kilitlenir'. Havuzda kullanılabilir iş parçacığı yoksa, istek kullanılabilir olana kadar beklemek zorundadır.

Eşzamansız denetleyicileriniz varsa, yine de havuzdan bir iş parçacığı alırlar, ancak isteği yerine getirirken iş parçacığından vazgeçebilirler, bir şey olmasını beklerken (ve bu iş parçacığı başka bir isteğe verilebilir) ve orijinal istek bir iş parçacığına ihtiyaç duyduğunda yine bir havuzdan alır.

Aradaki fark, çok uzun süren istekleriniz varsa (iş parçacığının bir şeyden yanıt beklediği yerde), temel istekleri bile hizmet etmek için havuzdaki iş parçacıklarınız tükenebilir. Zaman uyumsuz denetleyicileriniz varsa, daha fazla iş parçacığınız yok, ancak bekleyen iş parçacıkları havuza döndürülür ve diğer isteklere hizmet verebilir.

Bir neredeyse gerçek hayat örneği ... otobüse biniyor gibi düşünün, orada, ilk, bulaşırsa öder almak için bekleyen beş kişi var ve (sürücü kendi isteği servisli), sen almak oturur (sürücü hizmet verdiği isteğiniz) ancak paranızı bulamıyorsunuz; cebinizde beceriksizce sürücü senden vazgeçer ve sonraki iki kişiyi alır (isteklerini yerine getirir), paranızı bulduğunuzda sürücü sizinle tekrar uğraşmaya başlar (isteğinizi yerine getirir) - beşinci kişi işiniz bitti, ancak üçüncü ve dördüncü kişiler hizmete yarı yarıya ulaştıklarında servis yaptılar. Bu, sürücünün havuzdaki tek iplik olduğu ve yolcular için istekler olduğu anlamına gelir. İki sürücü olsaydı nasıl çalışacağını yazmak çok karmaşıktı ama hayal edebilirsiniz ...

Bir zaman uyumsuz denetleyici olmadan, paranızı ararken arkandaki yolcular yaşlarını beklemek zorunda kalacaklar, bu arada otobüs şoförü hiçbir iş yapmazdı.

Sonuç olarak, eğer pek çok insan parasının nerede olduğunu bilmiyorsa (yani sürücünün sorduğu bir şeye cevap vermek için uzun bir süre gerektiriyorsa), zaman uyumsuz denetleyiciler isteklerin işlenmesine yardımcı olabilir ve bazı süreçleri hızlandırabilir. Bir aysnc kontrolörü olmadan, ön taraftaki kişi tamamen ele alınana kadar herkes bekler. Ancak, MVC'de tek bir otobüste çok sayıda otobüs sürücüsüne sahip olduğunuzu unutmayın, bu nedenle asenkron otomatik bir seçim değildir.


8
Çok güzel bir benzetme. Teşekkür ederim.
Pittsburgh DBA

Açıklamayı beğendim. Teşekkürler
Omer Cansizoglu

Bunu açıklamanın mükemmel bir yolu.Teşekkür ederiz,
Anand Vyas

Darin'in cevabıyla birlikte verdiğiniz cevap, asenkron denetleyicilerin arkasındaki tüm mekanizmayı, ne olduğunu ve daha da önemlisi ne olmadığını özetler!
Nirman

Bu güzel bir benzetme, ama tek sorum şu: benzetmenizde cebinde dolaşan adam, uygulamamızda bir tür iş / işlem olacaktır ... yani ipliği serbest bıraktığımızda çalışan hangi süreçler? Somurtkan başka bir iş parçacığı mı? Peki burada ne kazanıyoruz?
Tomuke

10

Burada iki kavram var. Her şeyden önce, daha hızlı yürütmek için kodumuzu paralel olarak çalıştırabilir veya kullanıcının beklemesini önlemek için başka bir iş parçacığında kod planlayabiliriz. Sahip olduğunuz örnek

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

ikinci kategoriye girer. Kullanıcı daha hızlı yanıt alacaktır, ancak aynı işi yapması + iş parçacığını işlemesi gerektiği için sunucudaki toplam iş yükü daha yüksektir.

Buna başka bir örnek:

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Make async web request to twitter with WebClient.DownloadString()
    });

    Task.Factory.StartNew(() => { 
        //Make async web request to facebook with WebClient.DownloadString()
    });


    //wait for both to be ready and merge the results

    return View();
}

İstekler paralel çalıştığından, kullanıcının seri halinde yapıldıkları kadar beklemesi gerekmez. Ancak burada seri olarak çalıştırdığımızdan daha fazla kaynak kullandığımızı fark etmelisiniz, çünkü iş parçacığı beklemede iken kodu birçok iş parçacığında çalıştırıyoruz.

Bu bir istemci senaryosunda gayet iyi. Ve senkronize uzun koşu kodunu yeni bir görevde sarmak oldukça yaygındır (başka bir iş parçacığında çalıştırın) daha hızlı yapmak için kullanıcı arayüzünü duyarlı tutun veya paralize edin. Yine de bir iş parçacığı tüm süre boyunca kullanılır. Yüksek yüke sahip bir sunucuda, aslında daha fazla kaynak kullandığınız için bu geri tepebilir. İnsanlar sizi bu konuda uyardı

MVC'deki asenkron denetleyicilerin başka bir hedefi daha var. Buradaki amaç, hiçbir şey yapmadan (ölçeklenebilirliğe zarar verebilecek olan) iş parçacığı sitelerinin bulunmasından kaçınmaktır. Gerçekten sadece aradığınız API'ların zaman uyumsuz yöntemleri varsa önemlidir. WebClient.DowloadStringAsync () gibi.

Buradaki nokta, web isteği tamamlanıncaya kadar aynı veya yeni bir iş parçacığını alan geri çağrıyı arayacak ve isteği bitirene kadar iş parçacığınızın yeni istekleri işlemesine izin verebilmenizdir.

Umarım eşzamansız ve paralel arasındaki farkı anlarsınız. Paralel kodu, iş parçacığınızın bulunduğu kod olarak düşünün ve sonucu bekleyin. Eşzamansız kod, kod tamamlandığında size bildirilecek ve kod üzerinde tekrar çalışabileceğiniz bir kod olsa da, bu arada iş parçacığı başka işler de yapabilir.


6

Uygulamalar olabilir operasyonlar uyumsuz çalıştırırsanız daha iyi ölçek, ancak ek işlemleri hizmete kaynaklar mevcuttur yalnızca .

Zaman uyumsuz işlemler, mevcut bir işlem devam ettiği için hiçbir işlemi engellememenizi sağlar. ASP.NET, birden çok isteğin yan yana yürütülmesine izin veren eşzamansız bir modele sahiptir. İstekleri sıraya koymak ve bunları FIFO'yu işlemek mümkün olabilir, ancak sıraya alınan yüzlerce isteğiniz olduğunda ve her isteğin işlenmesi 100 ms sürdüğünde bu iyi ölçeklenmez.

Eğer trafik büyük hacme varsa, olabilir daha iyi durumda, eşzamansız sorgulama yapılarak olmamak isteklerine hizmet için hiçbir ek kaynaklar olabileceğinden . Yedek kaynak yoksa, istekleriniz sıraya girmeye zorlanır, katlanarak daha uzun sürebilir veya tamamen başarısız olur, bu durumda asenkron yük (muteksler ve bağlam değiştirme işlemleri) size hiçbir şey vermez.

ASP.NET'e gelince, bir seçeneğiniz yok - asenkron bir model kullanıyor, çünkü sunucu-istemci modeli için mantıklı olan şey bu. Daha iyi ölçeklendirmeye çalışmak için zaman uyumsuz desen kullanan kendi kodunuzu dahili olarak yazacak olsaydınız, tüm istekler arasında paylaşılan bir kaynağı yönetmeye çalışmadığınız sürece, zaten sarılmış oldukları için herhangi bir iyileştirme görmezsiniz. başka bir şeyi engellemeyen eşzamansız bir süreçte.

Sonuçta, aslında sisteminizde bir darboğazın nedenine bakana kadar özneldir. Bazen eşzamansız bir desenin nerelere yardımcı olacağı açıktır (sıradaki kaynak engellemesini engelleyerek). Sonuçta, yalnızca bir sistemi ölçmek ve analiz etmek nerede verimlilik elde edebileceğinizi gösterebilir.

Düzenle:

Örneğin, Task.Factory.StartNewçağrı .NET iş parçacığı havuzunda bir işlem kuyruğa girer. İş Parçacığı Havuzu iş parçacıklarının doğası yeniden kullanılmalıdır (çok sayıda iş parçacığı oluşturma / yok etme maliyetini önlemek için). İşlem tamamlandıktan sonra, iş parçacığı başka bir istek tarafından yeniden kullanılmak üzere havuza geri bırakılır (işlemlerinizde bazı nesneler oluşturmadığınız sürece Çöp Toplayıcı aslında dahil olmaz, bu durumda normal şekilde toplanır kapsam).

ASP.NET ile ilgili olarak, burada özel bir işlem yoktur. ASP.NET isteği, eşzamansız göreve gerek kalmadan tamamlanır. Senin parçacığı havuzu doymuş ise sadece endişe olabilir (yani şu anda orada isteğine hizmet hiçbir konu ve havuzun ayarları daha fazla iş parçacığı oluşturulmasına izin vermeyin) bu durumda istek engellenir, başlamak için bekleyen havuz iş parçacığı kullanılabilir hale gelene kadar görev .


Teşekkürler! Cevabınızı okuduktan sonra soruyu bir kod örneği ile düzenledim. Bir bakabilir misin?
tugberk

Orada benim için sihirli bir cümle var: Task.Factory.StartNewçağrı .NET iş parçacığı havuzunda bir işlem kuyruğa girecek. . Burada doğru olan bu bağlamda: 1-) Yeni bir iş parçacığı yaratır ve tamamlandığında bu iş parçacığı iş parçasına geri döner ve yeniden kullanılmasını bekler. 2-) Threadpool'dan bir iplik alır ve o iplik threadpool'a geri döner ve tekrar kullanılmasını bekler. 3-) En verimli yaklaşımı benimser ve her ikisini de yapabilir.
tugberk

1
İş parçacığı havuzu, gerektiğinde iş parçacıkları oluşturur ve kullanılmadıkları zaman iş parçacıklarını geri dönüştürür. Tam davranışı CLR sürümleri arasında değişmiştir. Bununla ilgili özel bilgileri burada bulabilirsiniz msdn.microsoft.com/en-us/library/0ka9477y.aspx
Paul Turner

Şimdi zihnimde şekillenmeye başlıyor. Yani, CLR iş parçacığı havuzunun sahibi değil mi? Örneğin, bir WPF uygulaması aynı zamanda iş parçacığı havuzu kavramına sahiptir ve orada havuzla da ilgilidir.
tugberk

1
İş Parçacığı Havuzu CLR içinde kendi şeyidir. Havuzun "farkında" olan diğer bileşenler, kendi havuzlarını oluşturmak ve yok etmek yerine, Konu Havuzu iş parçacıklarını (uygun olan yerlerde) kullandıklarını gösterir. Bir iş parçacığı oluşturmak veya yok etmek nispeten pahalı bir işlemdir, bu nedenle havuzu kullanmak kısa süreli işlemlerde büyük bir verimlilik kazancıdır.
Paul Turner

2

Evet, iş parçacığı havuzundan bir iş parçacığı kullanırlar. Aslında MSDN'den tüm sorularınızı ve daha fazlasını ele alacak oldukça mükemmel bir rehber var. Geçmişte oldukça yararlı buldum. Bunu kontrol et!

http://msdn.microsoft.com/en-us/library/ee728598.aspx

Bu arada, eşzamansız kod hakkında duyduğunuz yorumlar + öneriler bir tuz tanesi ile alınmalıdır. Yeni başlayanlar için, sadece zaman uyumsuz bir şey yapmak onu daha iyi ölçeklendirmez ve bazı durumlarda uygulama ölçeğinizi daha da kötüleştirebilir. "Çok büyük bir trafik hacmi" hakkında yayınladığınız diğer yorum da yalnızca belirli bağlamlarda doğrudur. Bu gerçekten işlemlerinizin ne yaptığına ve sistemin diğer bölümleriyle nasıl etkileşime girdiğine bağlıdır.

Kısacası, birçok insan zaman uyumsuzluğu hakkında çok fazla fikre sahiptir, ancak bağlam dışında doğru olmayabilirler. Ben tam sorunlara odaklanmayı söylemek ve kontrolörler zaman uyumsuz vb gerçekte ile başa ne olduğunu görmek için test temel performans yapardım senin uygulaması.


Bu belgeyi belki yüzlerce kez okudum ve hala çok fazla karışıklığım var (belki sorun benim, kim bilir). Etrafınıza baktığınızda, sorumda görebileceğiniz gibi ASP.NET MVC'de zaman uyumsuzluk hakkında çok fazla tutarsız yorum görüyorsunuz.
tugberk

son cümle için: bir denetleyici eylemi içinde, bir veritabanını 5 kez ayrı ayrı sorgulamak zorunda kaldım (zorundayım) ve hepsi yaklaşık 400 ms sürüyordu. Sonra AsyncController'ı uyguladım ve paralel olarak çalıştırdım. Tepki süresi dramatik olarak yakl. 200 ms. Ancak, ne kadar iş parçacığı oluşturduğuna dair bir fikrim yok, onlarla işim bittikten sonra bu iş parçacıklarına ne oluyor, GCgeliyor ve uygulandıktan sonra bellek sızıntısı olmayacak şekilde temizledim. Bu konuda herhangi bir fikir.
tugberk

bir hata ayıklayıcı ekleyin ve öğrenin.
AR

0

İlk şey onun değil MVC ama iş parçacığı havuzunu tutan IIS. Böylece MVC veya ASP.NET uygulamasına gelen herhangi bir istek iş parçacığı havuzunda tutulan iş parçacıklarından sunulur. Sadece uygulama Asynch yaparak farklı bir iş parçacığında bu eylemi çağırır ve diğer isteklerin alınabilmesi için iş parçacığını hemen serbest bırakır.

Aynı şeyi, MVC'de iş parçacığı açlığının nasıl oluştuğunu ve nasıl minimize edildiğini gösteren bir detay videosu ( http://www.youtube.com/watch?v=wvg13n5V0V0/ "MVC Asynch denetleyicileri ve iş parçacığı açlığı") ile açıkladım. Asynch denetleyicileri Ayrıca perfmon kullanarak istek kuyruklarını ölçtüm, böylece MVC asynch için istek kuyruklarının nasıl azaltıldığını ve Synch işlemleri için en kötü nasıl olduğunu görebilirsiniz.

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.