ASP.NET MVC 4 Sürümünde Zaman Uyumsuz Metotlar Kullanma

tarafından Rick Anderson

Bu öğreticide, Microsoft Visual Studio'nun ücretsiz bir sürümü olan Web için Visual Studio Express 2012'yi kullanarak zaman uyumsuz ASP.NET MVC Web uygulaması oluşturmanın temelleri öğretilecektir. Visual Studio 2012'de de kullanabilirsiniz.

GitHub'da bu öğretici için eksiksiz bir örnek sağlanır https://github.com/RickAndMSFT/Async-ASP.NET/

.NET 4.5 ile birlikte ASP.NET MVC 4 Denetleyicisi sınıfı, Task<ActionResult> türünde bir nesne döndüren zaman uyumsuz eylem yöntemleri yazmanızı sağlar. .NET Framework 4, Görev olarak adlandırılan zaman uyumsuz programlama kavramını kullanıma sunar ve MVC 4'ASP.NET Görevi destekler. Görevler, System.Threading.Tasks ad alanında Görev türü ve ilgili türler ile temsil edilir. .NET Framework 4.5, Görev nesneleriyle çalışmayı önceki zaman uyumsuz yaklaşımlardan çok daha az karmaşık hale getiren await ve zaman uyumsuz anahtar sözcüklerle bu zaman uyumsuz desteği kullanır. await anahtar sözcüğü, bir kod parçasının zaman uyumsuz olarak başka bir kod parçasında beklemesi gerektiğini belirten söz dizimsel kısaltmadır. Zaman uyumsuz anahtar sözcüğü, yöntemleri görev tabanlı zaman uyumsuz yöntemler olarak işaretlemek için kullanabileceğiniz bir ipucunu temsil eder. await, async ve Task nesnesinin birleşimi, .NET 4.5'te zaman uyumsuz kod yazmanızı çok daha kolay hale getirir. Zaman uyumsuz yöntemler için yeni modele Görev Tabanlı Zaman Uyumsuz Desen (TAP) adı verilir. Bu öğreticide await ve zaman uyumsuz anahtar sözcükleri ve Görev ad alanını kullanarak zaman uyumsuz programlama hakkında bilgi sahibi olduğunuz varsayılır.

await ve async anahtar sözcüklerini ve Görev ad alanını kullanma hakkında daha fazla bilgi için aşağıdaki başvurulara bakın.

İsteklerin İş Parçacığı Havuzu Tarafından İşlenme Şekli

Web sunucusunda, .NET Framework ASP.NET isteklerine hizmet vermek için kullanılan bir iş parçacığı havuzu tutar. bir istek geldiğinde, bu isteği işlemek için havuzdan bir iş parçacığı gönderilir. İstek zaman uyumlu olarak işlenirse, istek işlenirken isteği işleyen iş parçacığı meşgul olur ve bu iş parçacığı başka bir isteğe hizmet veremez.

İş parçacığı havuzu çok sayıda meşgul iş parçacığını barındıracak kadar büyük olabileceğinden bu sorun olmayabilir. Ancak, iş parçacığı havuzundaki iş parçacıklarının sayısı sınırlıdır (.NET 4.5 için varsayılan üst sınır 5.000'dir). Uzun süre çalışan isteklerin eşzamanlılığının yüksek olduğu büyük uygulamalarda, kullanılabilir tüm iş parçacıkları meşgul olabilir. Bu koşul, iş parçacığı açlığı olarak bilinir. Bu koşula ulaşıldığında, web sunucusu istekleri kuyruğa alır. İstek kuyruğu dolarsa, web sunucusu HTTP 503 durumu (Sunucu Çok Meşgul) olan istekleri reddeder. CLR iş parçacığı havuzu, yeni iş parçacığı eklemeleriyle ilgili sınırlamalara sahiptir. Eşzamanlılık çok yüksekse (yani, web siteniz aniden çok sayıda istek alabilir) ve yüksek gecikme süresine sahip arka uç çağrıları nedeniyle kullanılabilir tüm istek iş parçacıkları meşgulse, sınırlı iş parçacığı ekleme hızı uygulamanızın çok düşük yanıt vermesine neden olabilir. Ayrıca, iş parçacığı havuzuna eklenen her yeni iş parçacığının ek yükü vardır (örneğin, 1 MB yığın belleği). İş parçacığı havuzunun .NET 4.5 varsayılan en fazla 5.000 iş parçacığına büyüdüğü yüksek gecikmeli çağrılara hizmet vermek için zaman uyumlu yöntemler kullanan bir web uygulaması, bir uygulamanın aynı istekleri zaman uyumsuz yöntemler ve yalnızca 50 iş parçacığı kullanarak hizmete aktarabildiğinden yaklaşık 5 GB daha fazla bellek tüketir. Zaman uyumsuz iş yaparken her zaman bir iş parçacığı kullanmazsınız. Örneğin, zaman uyumsuz bir web hizmeti isteği yaptığınızda, ASP.NET zaman uyumsuz yöntem çağrısı ile await arasında herhangi bir iş parçacığı kullanmaz. İş parçacığı havuzunun yüksek gecikme süresine sahip isteklere hizmet vermek için kullanılması, büyük bir bellek ayak izine ve sunucu donanımının kötü kullanımına yol açabilir.

Zaman Uyumsuz İstekleri İşleme

Başlatma sırasında çok sayıda eşzamanlı istek gören veya ani yüke sahip olan bir web uygulamasında (eşzamanlılığın aniden arttığı durumlarda), web hizmeti çağrılarının zaman uyumsuz olarak yapılması uygulamanın yanıt hızını artırır. Zaman uyumsuz bir isteğin işlenmesi zaman uyumlu istek olarak aynı zaman alır. İstek, tamamlanması için iki saniye gerektiren bir web hizmeti çağrısı yaparsa, isteğin zaman uyumlu veya zaman uyumsuz olarak gerçekleştirilmesi iki saniye sürer. Ancak zaman uyumsuz bir çağrı sırasında, ilk isteğin tamamlanmasını beklerken iş parçacığının diğer isteklere yanıt vermesi engellenmez. Bu nedenle, uzun süre çalışan işlemleri çağıran çok sayıda eşzamanlı istek olduğunda zaman uyumsuz istekler istek kuyruğa alma ve iş parçacığı havuzu büyümesini engeller.

Zaman Uyumlu veya Zaman Uyumsuz Eylem Yöntemlerini Seçme

Bu bölümde, zaman uyumlu veya zaman uyumsuz eylem yöntemlerinin ne zaman kullanılacağına ilişkin yönergeler listelenir. Bunlar yalnızca yönergelerdir; zaman uyumsuz yöntemlerin performansa yardımcı olup olmadığını belirlemek için her uygulamayı ayrı ayrı inceleyin.

Genel olarak, aşağıdaki koşullar için zaman uyumlu yöntemleri kullanın:

  • İşlemler basit veya kısa sürelidir.
  • Basitlik verimlilikten daha önemlidir.
  • İşlemler, kapsamlı disk veya ağ yükü içeren işlemler yerine öncelikli olarak CPU işlemleridir. CPU'ya bağlı işlemlerde zaman uyumsuz eylem yöntemlerinin kullanılması hiçbir avantaj sağlamaz ve daha fazla ek yüke neden olur.

Genel olarak, aşağıdaki koşullar için zaman uyumsuz yöntemler kullanın:

  • Zaman uyumsuz yöntemlerle kullanılabilecek hizmetleri çağırıyorsunuz ve .NET 4.5 veya üzerini kullanıyorsunuz.
  • İşlemler CPU'ya bağlı yerine ağa veya G/Ç'ye bağlıdır.
  • Paralellik, kodun basitliğinden daha önemlidir.
  • Kullanıcıların uzun süre çalışan bir isteği iptal etmelerine olanak tanıyan bir mekanizma sağlamak istiyorsunuz.
  • İş parçacıklarını değiştirmenin avantajı bağlam anahtarının maliyetinden daha ağır bastığında. Genel olarak, zaman uyumlu yöntem hiçbir iş yapmadan ASP.NET istek iş parçacığında beklerse bir yöntemi zaman uyumsuz hale getirmeniz gerekir. Çağrıyı zaman uyumsuz hale getirerek, web hizmeti isteğinin tamamlanmasını beklerken ASP.NET istek iş parçacığı hiçbir çalışma yapmadan durdurulmuyor.
  • Test, engelleme işlemlerinin site performansında bir performans sorunu olduğunu ve IIS'nin bu engelleme çağrıları için zaman uyumsuz yöntemler kullanarak daha fazla istekte bulunabileceğini gösterir.

İndirilebilir örnek, zaman uyumsuz eylem yöntemlerinin etkili bir şekilde nasıl kullanılacağını gösterir. Sağlanan örnek, .NET 4.5 kullanılarak ASP.NET MVC 4'te zaman uyumsuz programlamanın basit bir gösterimini sağlamak için tasarlanmıştır. Örnek, ASP.NET MVC'de zaman uyumsuz programlama için bir başvuru mimarisi olarak tasarlanmamıştır. Örnek program, uzun süre çalışan web hizmeti çağrılarının benzetimini yapmak için Task.Delay çağrısı yapan ASP.NET Web API'si yöntemlerini çağırır. Çoğu üretim uygulaması, zaman uyumsuz eylem yöntemlerini kullanmanın bu kadar belirgin avantajlarını göstermez.

Az sayıda uygulama tüm eylem yöntemlerinin zaman uyumsuz olmasını gerektirir. Genellikle, birkaç zaman uyumlu eylem yöntemini zaman uyumsuz yöntemlere dönüştürmek, gereken iş miktarı için en iyi verimlilik artışını sağlar.

Örnek Uygulama

Örnek uygulamayı https://github.com/RickAndMSFT/Async-ASP.NET/GitHub sitesinden indirebilirsiniz. Depo üç projeden oluşur:

  • Mvc4Async: Bu öğreticide kullanılan kodu içeren ASP.NET MVC 4 projesi. WebAPIpgw hizmetine Web API çağrıları yapar.
  • WebAPIpgw: Denetleyicileri uygulayan Products, Gizmos and Widgets ASP.NET MVC 4 Web API projesi. WebAppAsync projesi ve Mvc4Async projesi için verileri sağlar.
  • WebAppAsync: Başka bir öğreticide kullanılan ASP.NET Web Forms projesi.

Gizmos Zaman Uyumlu Eylem Yöntemi

Aşağıdaki kod, gizmos listesini görüntülemek için kullanılan zaman uyumlu eylem yöntemini gösterir Gizmos . (Bu makalede gizmo, kurgusal bir mekanik cihazdır.)

public ActionResult Gizmos()
{
    ViewBag.SyncOrAsync = "Synchronous";
    var gizmoService = new GizmoService();
    return View("Gizmos", gizmoService.GetGizmos());
}

Aşağıdaki kod gizmo hizmetinin yöntemini gösterir GetGizmos .

public class GizmoService
{
    public async Task<List<Gizmo>> GetGizmosAsync(
        // Implementation removed.
       
    public List<Gizmo> GetGizmos()
    {
        var uri = Util.getServiceUri("Gizmos");
        using (WebClient webClient = new WebClient())
        {
            return JsonConvert.DeserializeObject<List<Gizmo>>(
                webClient.DownloadString(uri)
            );
        }
    }
}

yöntemi, GizmoService GetGizmos gizmos verilerinin listesini döndüren bir ASP.NET Web API'si HTTP hizmetine bir URI geçirir. WebAPIpgw projesi, Web API'sinin gizmos, widget ve product denetleyicilerinin uygulamasını içerir.
Aşağıdaki görüntüde örnek projedeki gizmos görünümü gösterilmektedir.

Gizmos

Zaman Uyumsuz Gizmos Eylem Yöntemi Oluşturma

Örnek, derleyicinin zaman uyumsuz programlama için gerekli karmaşık dönüşümleri korumakla sorumlu olmasını sağlamak için yeni zaman uyumsuz ve await anahtar sözcüklerini (.NET 4.5 ve Visual Studio 2012'de kullanılabilir) kullanır. Derleyici, C#'nin zaman uyumlu denetim akışı yapılarını kullanarak kod yazmanızı sağlar ve derleyici, iş parçacıklarını engellemek için geri çağırmaları kullanmak için gereken dönüştürmeleri otomatik olarak uygular.

Aşağıdaki kod zaman Gizmos uyumlu yöntemi ve GizmosAsync zaman uyumsuz yöntemi gösterir. Tarayıcınız HTML 5 <mark> öğesini destekliyorsa değişiklikleri sarı vurguda GizmosAsync görürsünüz.

public ActionResult Gizmos()
{
    ViewBag.SyncOrAsync = "Synchronous";
    var gizmoService = new GizmoService();
    return View("Gizmos", gizmoService.GetGizmos());
}
public async Task<ActionResult> GizmosAsync()
{
    ViewBag.SyncOrAsync = "Asynchronous";
    var gizmoService = new GizmoService();
    return View("Gizmos", await gizmoService.GetGizmosAsync());
}

zaman uyumsuz olmasına izin vermek GizmosAsync için aşağıdaki değişiklikler uygulandı.

  • yöntemi, derleyiciye gövdenin bölümleri için geri çağırmalar oluşturmasını ve döndürülen bir Task<ActionResult> öğesini otomatik olarak oluşturmasını söyleyen zaman uyumsuz anahtar sözcüğüyle işaretlenir.
  • Yöntem adına "Async" eklendi. "Zaman uyumsuz" ekleme gerekli değildir, ancak zaman uyumsuz yöntemler yazılırken kuraldır.
  • Dönüş türü olarak ActionResultTask<ActionResult>değiştirildi. dönüş türü Task<ActionResult> devam eden çalışmayı temsil eder ve yöntemi çağıranlara zaman uyumsuz işlemin tamamlanmasını beklemeleri için bir tanıtıcı sağlar. Bu durumda, çağıran web hizmetidir. Task<ActionResult> , bir sonuçla devam eden çalışmayı temsil eder ActionResult.
  • await anahtar sözcüğü web hizmeti çağrısına uygulandı.
  • Zaman uyumsuz web hizmeti API'sine ()GetGizmosAsync adı verildi.

Yöntem gövdesinin GetGizmosAsync içinde başka bir zaman uyumsuz yöntem GetGizmosAsync çağrılır. GetGizmosAsync veriler kullanılabilir olduğunda sonunda tamamlanacak bir Task<List<Gizmo>> döndürür. Gizmo verilerine sahip olana kadar başka bir şey yapmak istemediğinizden, kod görevi bekler ( await anahtar sözcüğünü kullanarak). await anahtar sözcüğünü yalnızca zaman uyumsuz anahtar sözcükle açıklama ek açıklamalı yöntemlerde kullanabilirsiniz.

await anahtar sözcüğü, görev tamamlanana kadar iş parçacığını engellemez. Yöntemin geri kalanını görevde geri çağırma olarak imzalar ve hemen döndürür. Beklenen görev sonunda tamamlandığında, bu geri çağırmayı çağırır ve böylece yöntemin yürütülmesini kaldığı yerden sürdürür. await ve async anahtar sözcüklerini ve Görev ad alanını kullanma hakkında daha fazla bilgi için bkz. zaman uyumsuz başvurular.

Aşağıdaki kod, GetGizmos ve GetGizmosAsync yöntemlerini göstermektedir.

public List<Gizmo> GetGizmos()
{
    var uri = Util.getServiceUri("Gizmos");
    using (WebClient webClient = new WebClient())
    {
        return JsonConvert.DeserializeObject<List<Gizmo>>(
            webClient.DownloadString(uri)
        );
    }
}
public async Task<List<Gizmo>> GetGizmosAsync()
{
    var uri = Util.getServiceUri("Gizmos");
    using (HttpClient httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync(uri);
        return (await response.Content.ReadAsAsync<List<Gizmo>>());
    }
}

Zaman uyumsuz değişiklikler yukarıdaki GizmosAsync'e yapılan değişikliklere benzer.

  • Yöntem imzasına zaman uyumsuz anahtar sözcüğüyle ek açıklama eklendi, dönüş türü olarak Task<List<Gizmo>>değiştirildi ve yöntem adına Async eklendi.
  • WebClient sınıfı yerine zaman uyumsuz HttpClient sınıfı kullanılır.
  • Await anahtar sözcüğü HttpClient zaman uyumsuz yöntemlerine uygulandı.

Aşağıdaki görüntüde zaman uyumsuz gizmo görünümü gösterilmektedir.

Zaman uyumsuz

Gizmos verilerinin tarayıcı sunusu, zaman uyumlu çağrı tarafından oluşturulan görünümle aynıdır. Tek fark, zaman uyumsuz sürümün ağır yükler altında daha yüksek performanslı olmasıdır.

Paralel Olarak Birden Çok İşlem Gerçekleştirme

Zaman uyumsuz eylem yöntemleri, bir eylemin birkaç bağımsız işlem gerçekleştirmesi gerektiğinde zaman uyumlu yöntemlere göre önemli bir avantaja sahiptir. Sağlanan örnekte, zaman uyumlu yöntem PWG(Ürünler, Pencere Öğeleri ve Gizmos için) ürünlerin, pencere öğelerinin ve gizmos'un listesini almak için üç web hizmeti çağrısının sonuçlarını görüntüler. Bu hizmetleri sağlayan ASP.NET Web API'si projesi, gecikme veya yavaş ağ çağrılarının benzetimini yapmak için Task.Delay kullanır. Gecikme 500 milisaniye olarak ayarlandığında zaman uyumsuz yöntemin PWGasync tamamlanması 500 milisaniyenin biraz üzerinde sürerken, zaman uyumlu PWG sürüm 1.500 milisaniyeyi aşıyor. Zaman uyumlu PWG yöntem aşağıdaki kodda gösterilmiştir.

public ActionResult PWG()
{
    ViewBag.SyncType = "Synchronous";
    var widgetService = new WidgetService();
    var prodService = new ProductService();
    var gizmoService = new GizmoService();

    var pwgVM = new ProdGizWidgetVM(
        widgetService.GetWidgets(),
        prodService.GetProducts(),
        gizmoService.GetGizmos()
       );

    return View("PWG", pwgVM);
}

Zaman uyumsuz PWGasync yöntem aşağıdaki kodda gösterilmiştir.

public async Task<ActionResult> PWGasync()
{
    ViewBag.SyncType = "Asynchronous";
    var widgetService = new WidgetService();
    var prodService = new ProductService();
    var gizmoService = new GizmoService();

    var widgetTask = widgetService.GetWidgetsAsync();
    var prodTask = prodService.GetProductsAsync();
    var gizmoTask = gizmoService.GetGizmosAsync();

    await Task.WhenAll(widgetTask, prodTask, gizmoTask);

    var pwgVM = new ProdGizWidgetVM(
       widgetTask.Result,
       prodTask.Result,
       gizmoTask.Result
       );

    return View("PWG", pwgVM);
}

Aşağıdaki görüntüde PWGasync yönteminden döndürülen görünüm gösterilmektedir.

pwgAsync

İptal Belirteci Kullanma

Geri dönen Task<ActionResult>zaman uyumsuz eylem yöntemleri iptal edilebilir, yani AsyncTimeout özniteliğiyle birlikte bir CancellationToken parametresi sağlanır. Aşağıdaki kod, GizmosCancelAsync 150 milisaniyelik zaman aşımına sahip yöntemini gösterir.

[AsyncTimeout(150)]
[HandleError(ExceptionType = typeof(TimeoutException),
                                    View = "TimeoutError")]
public async Task<ActionResult> GizmosCancelAsync(
                       CancellationToken cancellationToken )
{
    ViewBag.SyncOrAsync = "Asynchronous";
    var gizmoService = new GizmoService();
    return View("Gizmos",
        await gizmoService.GetGizmosAsync(cancellationToken));
}

Aşağıdaki kod, CancellationToken parametresini alan GetGizmosAsync aşırı yüklemesini gösterir.

public async Task<List<Gizmo>> GetGizmosAsync(string uri,
    CancellationToken cancelToken = default(CancellationToken))
{
    using (HttpClient httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync(uri, cancelToken);
        return (await response.Content.ReadAsAsync<List<Gizmo>>());
    }
}

Sağlanan örnek uygulamada İptal Belirteci Tanıtım bağlantısının seçilmesi yöntemini çağırır GizmosCancelAsync ve zaman uyumsuz çağrının iptalini gösterir.

Yüksek Eşzamanlılık/Yüksek GecikmeLi Web Hizmeti Çağrıları için Sunucu Yapılandırması

Zaman uyumsuz bir web uygulamasının avantajlarını hayata geçirmek için varsayılan sunucu yapılandırmasında bazı değişiklikler yapmanız gerekebilir. Zaman uyumsuz web uygulamanızı yapılandırırken ve stres testi yaparken aşağıdakileri göz önünde bulundurun.