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

tarafından Rick Anderson

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

Bu öğretici için adresinden eksiksiz bir örnek sağlanmıştır
https://github.com/RickAndMSFT/Async-ASP.NET/öğesini seçin.

.NET 4.5 ile birlikte ASP.NET 4.5 Web Sayfaları , Görev türünde bir nesne döndüren zaman uyumsuz yöntemleri kaydetmenizi sağlar. .NET Framework 4, Görev olarak adlandırılan zaman uyumsuz bir programlama kavramını kullanıma sunar ve ASP.NET 4.5 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 bir yüke sahip olan web uygulamalarında (eşzamanlılığın aniden arttığı durumlarda), web hizmeti çağrılarının zaman uyumsuz hale getirilmesi uygulamanızın yanıt hızını artırır. Zaman uyumsuz bir isteğin işlenmesi zaman uyumlu istek olarak aynı zaman alır. Örneğin, bir istek 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 Yöntemleri Seçme

Bu bölümde, zaman uyumlu veya zaman uyumsuz Yöntemlerin 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 yöntemlerin 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ığını engelliyorsa bir yöntemi zaman uyumsuz yapmalısınız. Çağrıyı zaman uyumsuz hale getirerek, web hizmeti isteğinin tamamlanmasını beklerken ASP.NET istek iş parçacığı hiçbir iş yapmadan engellenmez.

  • 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 yöntemlerin etkili bir şekilde nasıl kullanılacağını gösterir. Sağlanan örnek, ASP.NET 4.5'te zaman uyumsuz programlamanın basit bir gösterimini sağlamak için tasarlanmıştır. Örnek, ASP.NET 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 Yöntemler kullanmanın bu kadar belirgin avantajlarını göstermez.

Az sayıda uygulama tüm yöntemlerin zaman uyumsuz olmasını gerektirir. Genellikle, birkaç zaman uyumlu yöntemi 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.NETGitHub sitesinden indirebilirsiniz. Depo üç projeden oluşur:

  • WebAppAsync: Web API WebAPIpwg hizmetini kullanan ASP.NET Web Forms projesi. Bu öğreticinin kodunun çoğu bu projeden alınmıştı.
  • WebAPIpgw: Denetleyicileri uygulayan Products, Gizmos and Widgets ASP.NET MVC 4 Web API projesi. WebAppAsync projesi ve Mvc4Async projesi için verileri sağlar.
  • Mvc4Async: Başka bir öğreticide kullanılan kodu içeren ASP.NET MVC 4 projesi. WebAPIpwg hizmetine Web API çağrıları yapar.

Gizmos Zaman Uyumlu Sayfası

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

public partial class Gizmos : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        var gizmoService = new GizmoService();
        GizmoGridView.DataSource = gizmoService.GetGizmos();
        GizmoGridView.DataBind();
    }
}

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 sayfası gösterilmektedir.

Web API denetleyicilerine girilmiş olan ilgili ayrıntılarla birlikte gizmos tablosunu gösteren Gizmos web tarayıcısını eşitle sayfasının ekran görüntüsü.

Zaman Uyumsuz Gizmos Sayfası 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.

ASP.NET zaman uyumsuz sayfalar, özniteliği "true" olarak ayarlanmış Page yönergesini Async içermelidir. Aşağıdaki kod, GizmosAsync.aspx sayfası için özniteliği "true" olarak ayarlanmış Page yönergesini Async gösterir.

<%@ Page Async="true"  Language="C#" AutoEventWireup="true" 
    CodeBehind="GizmosAsync.aspx.cs" Inherits="WebAppAsync.GizmosAsync" %>

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

protected void Page_Load(object sender, EventArgs e)
{
   var gizmoService = new GizmoService();
   GizmoGridView.DataSource = gizmoService.GetGizmos();
   GizmoGridView.DataBind();
}

Zaman uyumsuz sürüm:

protected void Page_Load(object sender, EventArgs e)
{
    RegisterAsyncTask(new PageAsyncTask(GetGizmosSvcAsync));
}

private async Task GetGizmosSvcAsync()
{
    var gizmoService = new GizmoService();
    GizmosGridView.DataSource = await gizmoService.GetGizmosAsync();
    GizmosGridView.DataBind();
}

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

  • Page yönergesinin Async özniteliği "true" olarak ayarlanmalıdır.
  • RegisterAsyncTask yöntemi, zaman uyumsuz olarak çalışan kodu içeren zaman uyumsuz bir görevi kaydetmek için kullanılır.
  • Yeni GetGizmosSvcAsync yöntem, derleyiciye gövdenin bölümleri için geri çağırmalar oluşturmasını ve döndürülen bir Task öğesini otomatik olarak oluşturmasını söyleyen zaman uyumsuz anahtar sözcüğüyle işaretlenir.
  • Zaman uyumsuz yöntem adına "Async" eklendi. "Async" eklemek gerekli değildir, ancak zaman uyumsuz yöntemler yazılırken kuraldır.
  • Yeni GetGizmosSvcAsync yöntemin dönüş türü şeklindedir Task. dönüş türü Task devam eden çalışmayı temsil eder ve yöntemini çağıranlara zaman uyumsuz işlemin tamamlanmasını beklemeleri için bir tanıtıcı sağlar.
  • await anahtar sözcüğü web hizmeti çağrısına uygulandı.
  • Zaman uyumsuz web hizmeti API'sine ()GetGizmosAsync adı verildi.

Yöntem gövdesinin GetGizmosSvcAsync 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üğüyle ek açıklama eklenen 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 zaman uyumsuz başvurulara bakın.

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 (WebClient webClient = new WebClient())
    {
        return JsonConvert.DeserializeObject<List<Gizmo>>(
            await webClient.DownloadStringTaskAsync(uri)
        );
    }
}

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.
  • Zaman uyumsuz HttpClient sınıfı, zaman uyumlu WebClient sınıfı yerine kullanılır.
  • Await anahtar sözcüğü HttpClientGetAsync zaman uyumsuz yöntemine uygulandı.

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

Gizmos Async web tarayıcısı sayfasının ekran görüntüsü, web API denetleyicilerine girilmiş olarak ilgili ayrıntıları içeren gizmos tablosunu gösterir.

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.

RegisterAsyncTask Notları

ile RegisterAsyncTask bağlanmış yöntemler PreRender'ın hemen ardından çalıştırılır.

Aşağıdaki kodda gösterildiği gibi zaman uyumsuz geçersiz sayfa olaylarını doğrudan kullanırsanız:

protected async void Page_Load(object sender, EventArgs e) {
    await ...;
    // do work
}

artık olaylar yürütülürken tam denetime sahip olmazsınız. Örneğin, hem .aspx hem de . Master olayları tanımlar Page_Load ve bunlardan biri veya her ikisi de zaman uyumsuz olur, yürütme sırası garanti edilemez. Olay işleyicileri için aynı belirsiz sıra (örneğin async void Button_Click ) geçerlidir.

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

Zaman Uyumsuz Yöntemler, 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 PWG.aspx zaman uyumlu sayfası (Ürünler, Pencere Öğeleri ve Gizmos için), ürünlerin, pencere öğelerinin ve gizmos'ların 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 PWGasync.aspx sayfasının tamamlanması 500 milisaniyenin biraz üzerinde sürerken zaman uyumlu PWG sürüm 1.500 milisaniyeyi aşıyor. Zaman uyumlu PWG.aspx sayfası aşağıdaki kodda gösterilmiştir.

protected void Page_Load(object sender, EventArgs e)
{
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();

    var widgetService = new WidgetService();
    var prodService = new ProductService();
    var gizmoService = new GizmoService();

    var pwgVM = new ProdGizWidgetVM(
        widgetService.GetWidgets(),
        prodService.GetProducts(),
        gizmoService.GetGizmos()
       );
    WidgetGridView.DataSource = pwgVM.widgetList;
    WidgetGridView.DataBind();
    ProductGridView.DataSource = pwgVM.prodList;
    ProductGridView.DataBind();
    GizmoGridView.DataSource = pwgVM.gizmoList;
    GizmoGridView.DataBind();

    stopWatch.Stop();
    ElapsedTimeLabel.Text = String.Format("Elapsed time: {0}", 
        stopWatch.Elapsed.Milliseconds / 1000.0);
}

Arkasındaki zaman uyumsuz PWGasync kod aşağıda gösterilmiştir.

protected void Page_Load(object sender, EventArgs e)
{
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();
    RegisterAsyncTask(new PageAsyncTask(GetPWGsrvAsync));
    stopWatch.Stop();
    ElapsedTimeLabel.Text = String.Format("Elapsed time: {0}",
        stopWatch.Elapsed.Milliseconds / 1000.0);
}

private async Task GetPWGsrvAsync()
{
    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
       );

    WidgetGridView.DataSource = pwgVM.widgetList;
    WidgetGridView.DataBind();
    ProductGridView.DataSource = pwgVM.prodList;
    ProductGridView.DataBind();
    GizmoGridView.DataSource = pwgVM.gizmoList;
    GizmoGridView.DataBind();           
}

Aşağıdaki görüntüde zaman uyumsuz PWGasync.aspx sayfasından döndürülen görünüm gösterilmektedir.

Pencere Öğeleri, Ürünler ve Gizmos tablolarını gösteren Zaman Uyumsuz Pencere Öğeleri, Ürünler ve Gizmos web tarayıcısı sayfasının ekran görüntüsü.

İptal Belirteci Kullanma

Geri dönen Taskzaman uyumsuz yöntemler iptal edilebilir, başka bir ifadeyle Page yönergesinin özniteliğiyle AsyncTimeout birlikte bir CancellationToken parametresi alınıyor. Aşağıdaki kodda GizmosCancelAsync.aspx sayfası ve saniye zaman aşımı gösterilir.

<%@ Page  Async="true"  AsyncTimeout="1" 
    Language="C#" AutoEventWireup="true" 
    CodeBehind="GizmosCancelAsync.aspx.cs" 
    Inherits="WebAppAsync.GizmosCancelAsync" %>

Aşağıdaki kod GizmosCancelAsync.aspx.cs dosyasını gösterir.

protected void Page_Load(object sender, EventArgs e)
{
    RegisterAsyncTask(new PageAsyncTask(GetGizmosSvcCancelAsync));
}

private async Task GetGizmosSvcCancelAsync(CancellationToken cancellationToken)
{
    var gizmoService = new GizmoService();
    var gizmoList = await gizmoService.GetGizmosAsync(cancellationToken);
    GizmosGridView.DataSource = gizmoList;
    GizmosGridView.DataBind();
}
private void Page_Error(object sender, EventArgs e)
{
    Exception exc = Server.GetLastError();

    if (exc is TimeoutException)
    {
        // Pass the error on to the Timeout Error page
        Server.Transfer("TimeoutErrorPage.aspx", true);
    }
}

Sağlanan örnek uygulamada GizmosCancelAsync bağlantısı seçildiğinde GizmosCancelAsync.aspx sayfası çağrılır ve zaman uyumsuz çağrının iptali (zaman aşımına uğrarak) gösterilir. Gecikme süresi rastgele bir aralık içinde olduğundan, zaman aşımı hata iletisini almak için sayfayı birkaç kez yenilemeniz gerekebilir.

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ı gerçekleştirmek 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.

Katkıda Bulunanlar