2014-08-28 23 views
8

Ben eylem yöntemine içinde başka DİNLENME hizmetine iki web istekleri gerçekleştirmek için gerekli bir ASP.NET WebAPI denetleyicisi vardı Geçenlerde bir durum vardı. Ben HttpClient tüm web istekleri zaman uyumsuz olmak zorunda kullanıyordum ÇünküEşzamanlı/beklemeli çağrı zincirleme nasıl çalışır?

public class FooController : ApiController 
{ 

    public IHttpActionResult Post(string value) 
    { 
     var results = PerformWebRequests(); 
     // Do something else here... 
    } 

    private IEnumerable<string> PerformWebRequests() 
    { 
     var result1 = PerformWebRequest("service1/api/foo"); 
     var result = PerformWebRequest("service2/api/foo"); 

     return new string[] { result1, result2 }; 
    } 

    private string PerformWebRequest(string api) 
    { 
     using (HttpClient client = new HttpClient()) 
     { 
      // Call other web API and return value here... 
     } 
    } 

} 

: Ben işlevselliği bu örnekteki gibi biraz görünüyordu ayrı yöntemler ile tertemiz bir ayrılmış olması için kodumu yazmıştı. Daha önce hiç uyumsuz/beklemedim, bu yüzden anahtar kelimelere safça eklemeye başladım. Önce PerformWebRequest(string api) yöntemine async anahtar kelime eklendi ama sonra arayan PerformWebRequests() yöntem await kullanmak için çok async olması gerektiğini şikayet etti. Bu yüzden async'u yaptım ama şimdi bu yöntemin arayıcısı async olmalıdır, vb. Bilmek istiyorum ne

her şey sadece çalışmak async işaretlenmesi gerekir ne kadar tavşan deliğine mi? Şüphesiz, bir şeyin eşzamanlı olarak çalıştığı bir noktaya gelirdi, bu durumda nasıl güvenli bir şekilde ele alınır? Zaten kilitlenmelere neden olabileceğinden, Task.Result numaralı telefonu aramanın kötü bir fikir olduğunu okudum.

+0

Bunun bir çoğaltmaya hak kazanıp kazanmadığını tartışıyorum: http://stackoverflow.com/questions/9208921/async-on-main-method-of-console-app – spender

+1

Bu harika videoyu kanalda async ile izleyebilirsiniz. - http://channel9.msdn.com/events/TechDays/Techdays-2014-the-Netherlands/Async-programming-deep-dive – terrybozzio

+1

Bir başka mükemmel kaynak, Jon Skeet'in http: // codeblog tarafından yayınlanan blog yayınlarının Eduasync dizisidir. jonskeet.uk/category/eduasync/ – softveda

cevap

13

her şey sadece çalışmak zaman uyumsuz işaretlenmesi gerekir ne kadar tavşan deliğine mi? Şüphesiz şey eşzamanlı

No çalıştırmak zorunda olduğu bir noktaya orada gelirdi şey senkronize çalışan bir nokta olmamalı ve bu zaman uyumsuz tüm hakkında ne olduğunu. ifade "Tüm yol zaman uyumsuz" aslında çağrı yığını kadar tüm yol anlamına gelir. senin gerçekten asenkron metot çalışır iken rabit delik, There is no Thread aşağı derin gidince çünkü

zaman uyumsuz bir ileti işlemek

, siz, ileti döngüsü süreci isteklerini izin veriyorsun.

Örneğin

, bir zaman uyumsuz düğmesini tıklatın olay işleyicisi olduğunda:

private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    await DoWorkAsync(); 
    // Do more stuff here 
} 

private Task DoWorkAsync() 
{ 
    return Task.Delay(2000); // Fake work. 
} 

düğmesi tıklandığında, ilk await isabet kadar senkronize olarak çalışır. Vurulduktan sonra, yöntem kontrolciyi arayana geri getirecektir, bu da düğme olay işleyicisinin UI iş parçacığını serbest bırakacağı anlamına gelir, bu da mesaj döngüsünü bu sırada daha fazla istekleri işlemek için serbest bırakır.

aynı HttpClient kullanımınız için de geçerli. Örneğin, varsa:

public async Task<IHttpActionResult> Post(string value) 
{ 
    var results = await PerformWebRequests(); 
    // Do something else here... 
} 

private async Task<IEnumerable<string>> PerformWebRequests() 
{ 
    var result1 = await PerformWebRequestAsync("service1/api/foo"); 
    var result = await PerformWebRequestAsync("service2/api/foo"); 

    return new string[] { result1, result2 }; 
} 

private async string PerformWebRequestAsync(string api) 
{ 
    using (HttpClient client = new HttpClient()) 
    { 
     await client.GetAsync(api); 
    } 

    // More work.. 
} 

görün async kelime POST isteği işlerken ana yönteme giden tüm yol boyunca nasıl gittiğini. Bu şekilde, async http isteği ağ aygıtı sürücüsü tarafından ele alınırken, iş parçacığınız ASP.NET ThreadPool'a döner ve bu sırada daha fazla istekte bulunmak ücretsizdir. Yeni ön plan iş parçacığı dönmeye sürece

A Konsol Uygulaması, Main yöntem sonlandırıldığında beri, özel bir durumdur, uygulama sona erer.Orada, tek çağrı bir async çağrısı ise, Task.Wait veya Task.Result'u açıkça kullanmanız gerektiğinden emin olmanız gerekir. Ancak, bu durumda varsayılan SynchronizationContext, kilitlenmeye neden olma şansının olmadığı ThreadPoolSynchronizationContext'dur. (Örneğin, bir konsol uygulaması gibi) egzotik kullanım durumunda olduğu sürece

Sonuç olarak, zaman uyumsuz yöntemler , zaman uyumsuz ipliğin sağlayan tüm yol akmalıdır, yığının üstünde uyumlu olarak işlenmelidir Mümkün olduğunda serbest bırakılmalıdır.

+0

İyi cevap. Bir optimizasyon olarak, 'PerformWebRequestAsync' çağrılarının paralel olarak yapılabilmesi ve Task.WhenAll ile beklenmesi durumları da yapılabilir. Tabii ki, bu, birinci aramanın sonucunun, ikinci aramanın talebi ile gerekli olmadığını varsayar. –

+0

@MattJohnson Teşekkürler Matt, bunu düşündüm, ama OP'nin orijinal kodunu çok fazla değiştirmek istemedim, cevabın içeriğine dahil etmek için. –

+1

Teşekkür ederim @YuvalItzchakov, bu bana özellikle de bir 'Main()' metodunda (ayrıca merak ettiğim gibi) kullanıldığında bana çok şey anlatıyor. Bana göre "async/await" bunu çok daha kolay hale getirirken, sadece bir "async" yöntemi eklemek için değiştirmek için ne kadar kod değiştirmeniz gerektiğini anlamak gibi, düşünmek için de düşünmek için tasarımla ilgili düşünceler var. –

0

Sen asenkron isteklerin hepsi işleyebilir bir ileti döngüsü ulaşmak çağrı yığını, çok üstüne "tüm yol kadar zaman uyumsuz" gerekir. Bilmek istiyorum ne