SORU
27 NİSAN 2012, Cuma


HttpClient.(...) GetAsync asla kullanma/zaman uyumsuz bekliyor ne zaman döner

Düzenleme:This question aynı sorun olabilir gibi görünüyor, ama hiç bir yanıt vardır

Düzenleme:Test çalışması 5 görev WaitingForActivation durumda kalmış gibi görünüyor.

Bazı garip davranış Sistemini kullanarak karşılaştım.Net.Http.İçinde HttpClient .NET "" bir çağrı (örneğin) httpClient.GetAsync(...) asla geri gelmeyecek. sonuç bekleyen nerede 4.5 -

Bu sadece yeni zaman uyumsuz/kullanarak dil işlevselliği ve Görevler bekliyor, bazı durumlarda API oluşur - kodu her zaman tek devamı kullanırken iş gibi görünüyor.

Burada sorun üretir bazı kod - yeni içine bu damla "MVC 4 WebApi projesi" Görsel olarak aşağıdaki duyurmak için Studio 11 bitiş:

/api/test1
/api/test2
/api/test3
/api/test4
/api/test5 <--- never completes
/api/test6

Uç noktaları burada her hiç tamamlar aynı verileri (yanıtı stackoverflow.com gelen başlıklar) /api/test5 dışında dönün.

HttpClient sınıfı bir hata karşılaşmış, ya da bir şekilde API kötüye mıyım?

Kod yeniden oluşturmak için:

public class BaseApiController : ApiController
{
    /// <summary>
    /// Retrieves data using continuations
    /// </summary>
    protected Task<string> Continuations_GetSomeDataAsync()
    {
        var httpClient = new HttpClient();

        var t = httpClient.GetAsync("http://stackoverflow.com", HttpCompletionOption.ResponseHeadersRead);

        return t.ContinueWith(t1 => t1.Result.Content.Headers.ToString());
    }

    /// <summary>
    /// Retrieves data using async/await
    /// </summary>
    protected async Task<string> AsyncAwait_GetSomeDataAsync()
    {
        var httpClient = new HttpClient();

        var result = await httpClient.GetAsync("http://stackoverflow.com", HttpCompletionOption.ResponseHeadersRead);

        return result.Content.Headers.ToString();
    }
}

public class Test1Controller : BaseApiController
{
    /// <summary>
    /// Handles task using Async/Await
    /// </summary>
    public async Task<string> Get()
    {
        var data = await Continuations_GetSomeDataAsync();

        return data;
    }
}

public class Test2Controller : BaseApiController
{
    /// <summary>
    /// Handles task by blocking the thread until the task completes
    /// </summary>
    public string Get()
    {
        var task = Continuations_GetSomeDataAsync();

        var data = task.GetAwaiter().GetResult();

        return data;
    }
}

public class Test3Controller : BaseApiController
{
    /// <summary>
    /// Passes the task back to the controller host
    /// </summary>
    public Task<string> Get()
    {
        return Continuations_GetSomeDataAsync();
    }
}

public class Test4Controller : BaseApiController
{
    /// <summary>
    /// Handles task using Async/Await
    /// </summary>
    public async Task<string> Get()
    {
        var data = await AsyncAwait_GetSomeDataAsync();

        return data;
    }
}

public class Test5Controller : BaseApiController
{
    /// <summary>
    /// Handles task by blocking the thread until the task completes
    /// </summary>
    public string Get()
    {
        var task = AsyncAwait_GetSomeDataAsync();

        var data = task.GetAwaiter().GetResult();

        return data;
    }
}

public class Test6Controller : BaseApiController
{
    /// <summary>
    /// Passes the task back to the controller host
    /// </summary>
    public Task<string> Get()
    {
        return AsyncAwait_GetSomeDataAsync();
    }
}

CEVAP
27 NİSAN 2012, Cuma


API yanlış kullanıyorsun.

Durum şöyle: ASP.NET sadece bir konuyu bir anda bir isteği işleyebilir. Gerekirse bazı paralel işlem yapabilirsiniz (iş parçacığı havuzu iş parçacığı ek borçlanma), ancak yalnızca bir iş parçacığı istek İçeriği (Ek iş parçacığı isteği olmayan içerik) olurdu.

Bu managed by the ASP.NET SynchronizationContext.

8 ** varsayılan olarak, bir Task yöntem bir özgeçmiş SynchronizationContext (ya da SynchronizationContext yok TaskScheduler, Bir esir) yakaladı. Normalde, bu sizin istediğiniz şey: zaman uyumsuz bir denetleyici eylem 13* *bir şey olacak, ve devam ettiğinde, isteği ile kapsamında kaldığı yerden devam eder.

Yani, burada test5 neden başarısız oldu:

  • Test5Controller.Get AsyncAwait_GetSomeDataAsync (ASP.NET istek dahilinde) yürütür.
  • AsyncAwait_GetSomeDataAsync HttpClient.GetAsync (ASP.NET istek dahilinde) yürütür.
  • HTTP isteği gönderilir ve HttpClient.GetAsync Task tamamlanmamış verir.
  • AsyncAwait_GetSomeDataAsync tam olmadığından Task;, AsyncAwait_GetSomeDataAsync döner Task tamamlanmamış bekliyor.
  • Test5Controller.GetengellerTask o kadar geçerli iş parçacığı tamamlar.
  • HTTP yanıtı gelir ve Task HttpClient.GetAsync tarafından döndürülen tamamlandı.
  • AsyncAwait_GetSomeDataAsync ASP.NET istek dahilinde devam ettirmek için çalışır. Ancak, bu bağlamda bir konu var: iplik Test5Controller.Get bloke.
  • Kilitlenme.

Diğerleri Peki:

  • (test1, test2, test3): Continuations_GetSomeDataAsync programları iş parçacığı havuzu için devamıdışarıdabu ASP.NET bağlam isteği. Bu Task Continuations_GetSomeDataAsync tarafından döndürülen yeniden girmek zorunda kalmadan istek içeriği tamamlamak için izin verir.
  • (test4 test6): Task Beribekliyordu, ASP.NET istek iş parçacığı bloke olmaması. Bu AsyncAwait_GetSomeDataAsync devam etmek için hazır olduğunda ASP.NET istek içeriği kullanmak için izin verir.

Ve burada en iyi uygulamalar:

  1. "Kütüphane yöntemleri" async mümkün olduğunda ConfigureAwait(false) kullanın. Senin durumunda, bu AsyncAwait_GetSomeDataAsync var result = await httpClient.GetAsync("http://stackoverflow.com", HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); olarak değiştirin
  2. Tasks blok yok; async tüm yol aşağı. Diğer bir deyişle, GetResult yerine await (Task.Result Task.Wait await ile değiştirilmelidir) kullanın.

Bu şekilde, hem faydaları: devamı (geri kalan AsyncAwait_GetSomeDataAsync yöntem) bir temel parçacığı havuzu iş parçacığı yok girmek için ASP.NET istek içeriği; ve denetleyici kendisi async (hangi değil blok isteği iş parçacığı).

Daha fazla bilgi için:

  • Benim Task awaiters nasıl kısa bir açıklama içerir async/await intro post, SynchronizationContext.
  • Bu kavramlarla ilgili daha fazla ayrıntı gider, 62**,. Ayrıca bakınız Await, and UI, and deadlocks! Oh, my!yokASP.NET SynchronizationContext sadece bir iş parçacığı bağlama isteği bir anda sınırlar için bir kullanıcı arayüzü yerine, ASP.NET içinde olsan da burada geçerli.
  • Bu 64**.
  • Stephen* *65 so does Lucian Wischik Toub.

Güncelleme 2012-07-13:Dahil bu cevap into a blog post.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • LiteralMSPaint

    LiteralMSPai

    27 EKİM 2010
  • Nickcidious

    Nickcidious

    6 HAZİRAN 2011
  • Semantic Mastery

    Semantic Mas

    30 EKİM 2013