2015-01-15 10 views
6

Eşzamansız yöntemler eklemek için bir kütüphaneyi değiştiriyorum. Should I expose synchronous wrappers for asynchronous methods?'dan, eşzamanlı yöntemi çağırırken Task.Result etrafında bir sarıcı yazmamam gerektiğini bildiriyor. Ancak, her iki seçeneği de kitaplıkta tutmak istediğimizden, uyumsuzluk yöntemleri ve eşitleme yöntemleri arasında çok fazla kodun çoğaltılmasına neden gerek yok? Örneğin kitaplık şu anda TextReader.Read yöntemini kullanır. Eşzamansız değişimin bir parçası olarak, TextReader.ReadAsync yöntemini kullanmak istiyoruz. Bu, kütüphanelerin özünde bulunduğundan, eşzamanlı ve eşzamansız yöntemler arasında bir çok kodu çoğaltmam gerekecek gibi görünüyordu (kodu DRY'yi olabildiğince saklamak istiyoruz). Ya da, kodu karıştıran ve TPL'nin düzeltmeye çalıştığı izlenimi veren PreRead ve PostRead yöntemlerinde onları yeniden düzenlemem gerekiyor.Kütüphanelerde eşzamanlı ve eşzamansız yöntemler yazmak ve onu korumak için desen DRY

yöntemini yalnızca Task.Return()'da kaydırma hakkında düşünüyorum. Bir görev olmakla birlikte, TPL'deki gelişmeler farklı bir iş parçacığına geçmemelidir ve ben hala normalde olduğu gibi kodun çoğunu beklemede olan async'i kullanabilirim. Daha sonra sadece Task.Result veya Wait() olmak için eşzamanlı bir sarıcı olması iyi olur mu?

.net kitaplığındaki diğer örneklere baktım. StreamReader, async ve async olmayanlar arasındaki kodu çoğaltıyor gibi görünüyor. MemoryStream, Task.FromResult yapar.

Ayrıca heryerde planlama yapmak için sadece bir kütüphane olarak ConfigureAwait(false) ekleyebilirim.

Güncelleme:

ben çoğaltılamaz kod bahsediyorum ne

public decimal ReadDecimal() 
{ 
    do 
    { 
      if (!Read()) 
      { 
       SetInternalProperies() 
      } 
      else 
      { 
       return _reader.AsDecimal(); 
      } 
     } while (_reader.hasValue) 
} 

public async Task<decimal> ReadDecimalAsync() 
{ 
    do 
    { 
      if (!await ReadAsync()) 
      { 
       SetInternalProperies() 
      } 
      else 
      { 
       return _reader.AsDecimal(); 
      } 
     } while (_reader.hasValue) 
    } 

Bu küçük bir örnek ama sadece kod değişikliği bekleyen ve görev görebilirsiniz olduğunu.

Açıkça belirtmek gerekirse, kitaplıktaki her yerde async/bekletme ve TPL kullanarak kodlamak istiyorum ancak yine de eski eşitleme yöntemlerinin de çalışması gerekiyor. Ben sadece Task.FromResult() eşitleme yöntemleri ile ilgili değilim. Ben eşitleme yöntemini istiyor ve kökünde de o zaman bir görev olarak senkron bir sarmalayıcı sahip olmak Tamam olur

public decimal ReadDecimal() 
{ 
    return ReadDecimalAsyncInternal(true).Result; 
} 

public async Task<decimal> ReadDecimal() 
{ 
    return await ReadDecimalAsyncInternal(false); 
} 

private async Task<decimal> ReadDecimalAsyncInternal(bool syncRequest) 
{ 
    do 
    { 
      if (!await ReadAsync(syncRequest)) 
      { 
       SetInternalProperies() 
      } 
      else 
      { 
       return _reader.AsDecimal(); 
      } 
     } while (_reader.hasValue) 
} 

private Task<bool> ReadAsync(bool syncRequest) 
{ 
    if(syncRequest) 
    { 
     return Task.FromResult(streamReader.Read()) 
    } 
    else 
    { 
     return StreamReader.ReadAsync(); 
    } 
} 
+2

Senkronize ve zaman uyumsuz bir yöntem sürümünü neden göstermek istiyorsunuz? Bir işlem senkron veya asenkron olabilir. İkisi de olamaz. Doğru olanı seçin, ikisini de değil. Daha sonra müşteri kodu ile, o zaman arayabilirsin. –

+0

Bu bir kütüphanedir. Bunu kullanan mevcut kodumuz var ve bunları değiştirmek zorunda kalmak istemiyoruz. Biz size pozitif bir şey verir – CharlesNRice

+1

A Task.Result sarıcı Library.Method ve Library.MethodAsync gibi kütüphaneye "zaman uyumsuz" yöntemi ekliyoruz TextReader.Read ve TextReader.ReadAsync aynı şey. Bekleme, bu görevde depolanan değeri eşzamanlı olarak alacaktır. Yöntem imzası yanıltıcıdır. Yalnızca asenkron içsel olarak bulunan async yöntemlerini açığa çıkarın. – usr

cevap

1

gibi bayrak şeyi kontrol yazan bir bayrak başlamıştı düşünüyordum ne. Sonuç veya Bekle()?

Async IO'nun neyle ilgili olduğunu anlamak zorundasınız. Bu kod çoğaltma hakkında değil, iş doğal olarak asenkronize olduğunda herhangi bir iş parçacığına ihtiyacınız olmaması gerçeğinden yararlanma hakkında.

Senkronize kodunuzu bir görevle kaydırırsanız, bu avantajdan kaçıyorsunuz demektir. Ayrıca, beklenen çağrının arayana tekrar kontrol sağladığını varsayarsanız, API arayanlarınızı yanıltmasın.

Düzenleme:

Kişisel örnekler benim açımdan güçlendirir. Görevleri kullanmayın. Eşzamanlı apis kendiliğinden tamamen iyidir, gerekmediğinde TPL kullanımını zorlamazlar, eğer kod tabanı kod satırının 2 katına çıkarsa neden olur.

doğru zaman uyumsuz api uygulamak için zaman ayırın. Zaman uyumsuz kodunu engellemeyin, yığının en altına kadar akmasını sağlayın.

+0

Ben tam tersini yapmak istiyorum. TPL async bekleme kodunu kullanarak yazmak istiyorum, ancak şu anda senkronizasyon kodu kullanılarak yazılmış mevcut kütüphaneyi ayıramam. Örnek şu anda TextReader.ReadAsync'i kullanmakta olduğumuz TextReader.Read'i kullanmak istiyorum. Tüm yöntem çağrılarının Görev <> aramalarını beklemesini sağlayacağım. Ancak hala eski senkronizasyon yöntemlerini desteklemem gerekiyor ve Async kodunu kullanmak istedim ve sadece Sonuç veya Bekle() üzerine tıklamak istedim. Ama bu da kaşlarını çatmış görünüyor. – CharlesNRice

+2

@CharlesNop, lib'inizdeki senkronize olanlara ek olarak uyumsuzluk yöntemleri eklemek ister misiniz?Bağlantınız olan makale tam olarak bu konuda konuşuyor. Senkronizasyon sarmalayıcıları veya başka bir şekilde senkronize olmayanlar ekleme. Makale neden sorunuzu cevaplamıyor? – usr

+0

Sonuçların üzerinde engel yok. Birçok hata ve kilitlenme için bir kaynak. Eşzamanlı sürümü senkronize edin ve yukarıdan aşağıya doğru * tüm yolla * * async kullanarak async API'sini yazın. –

4

Sen lib senkron olanlar için ek olarak zaman uyumsuz yöntemleri eklemek istiyorum. Bağlantınız olan makale tam olarak bu konuda konuşuyor. Her iki sürüm için özel kod oluşturmanızı tavsiye ederiz.

  1. zaman uyumsuz yöntemleri düşük gecikmeli olmalıdır çünkü:

    Şimdi bu tavsiye genellikle verilir. Verimlilik için async IO'u dahili olarak kullanmalıdırlar.
  2. Senkronizasyon yöntemleri, verimlilik nedenleriyle IO'yu dahili olarak senkronize etmelidir.

Eğer arayanları yanlış yorumlara yol açabileceği sarmalayıcılarını oluşturursanız.

Şimdi, sonuçlarla ilgili sorun yoksa sarıcıları her iki şekilde oluşturmak için geçerli stratejisidir. Kesinlikle çok fazla kod kaydeder. Ancak senkronizasyona mı yoksa async sürümüne mi tercih edileceğine karar vermelisiniz. Diğeri ise daha az verimli olacak ve varolan performansa dayalı bir neden olmayacaktır. uygulama kalitesi yüksek olduğundan

nadiren BCL bu bulacaksınız. Ancak, örneğin, ADO.NET 4.5'ün SqlConnection sınıfı, eşzamanlı senkronizasyon özelliğini kullanır. SQL çağrısı yapmanın maliyeti senkronizasyon yükünden çok daha büyüktür. Bu bir kullanım örneği. MemoryStream, eşzamanlı olarak eşzamanlı olarak kullanıldığından (tür), yalnızca CPU'nun çalışmasıdır, ancak Stream'u uygulamalıdır.

havai aslında nedir? Saniyede 100 milyon Task.FromResult ve saniyede milyonlarca sıfır çalışan Task.Run çalışmayı deneyebilirsiniz. Birçok şeyle kıyaslandığında küçük bir yük.

İlgili konular