2013-10-27 16 views
7

Azure Storage Client kütüphanesi 2.1 ile çalışma, Tablo depolama eşzamansız sorgu sorgusu üzerinde çalışıyorum.Azure Table Storage ile Table.ExecuteQuerySegmentedAsync() nasıl kullanılır?

public async Task<List<TAzureTableEntity>> GetByPartitionKey(string partitionKey) 
{ 
    var theQuery = _table.CreateQuery<TAzureTableEntity>() 
         .Where(tEnt => tEnt.PartitionKey == partitionKey); 
    TableQuerySegment<TAzureTableEntity> querySegment = null; 
    var returnList = new List<TAzureTableEntity>(); 
    while(querySegment == null || querySegment.ContinuationToken != null) 
    { 
     querySegment = await theQuery.AsTableQuery() 
            .ExecuteSegmentedAsync(querySegment != null ? 
             querySegment.ContinuationToken : null); 
     returnList.AddRange(querySegment); 
    } 
    return returnList; 
} 

o kadar Tablo Storage yuvarlak gezileri çok olacak geri geliyor büyük bir veri kümesi olmadığını varsayalım: Bu kodu yarattı. Sahip olduğum problem, bir veri setini beklediğimiz, onu bir bellek içi listeye eklediğimiz, daha fazla veri beklediğimiz, onu aynı listeye eklediğimiz, daha fazla veri beklediğimiz, listeye eklediğimiz ... ve böylece vb. Neden bir Task.Factory.StartNew() düzenli bir TableQuery etrafında wrap? böylece gibi:

public async Task<List<TAzureTableEntity>> GetByPartitionKey(string partitionKey) 
{ 
    var returnList = await Task.Factory.StartNew(() => 
               table.CreateQuery<TAzureTableEntity>() 
               .Where(ent => ent.PartitionKey == partitionKey) 
               .ToList()); 
    return returnList; 
} 

de genişlemiş biz ileri geri çok SynchronizationContext sıçrayan değil konum gibi bu şekilde görünüyor. Yoksa gerçekten önemli mi?

Düzenleme

yukarıda belirtilen iki senaryo arasındaki fark nedir Soru Rephrase için?

+1

Bunu kendi zaman uyumsuz stilini "segmenti" koymak ve kullanma diyoruz (yanlış) ConfigureAwait. –

+0

@PauloMorgado - İronik olarak aslında TableQuerySegement ve deyim zaten ayrı bir yöntemde ancak ben Görevdeki ConfigureAwait (false) yöntemini bilmiyordum. Bahşiş için teşekkürler! – Hallmanac

+2

ConfigureAwait (false) tüm kitaplık kodları için önerilir ve tüm kullanıcı arabirimi olmayan uygulama kodlarına genişletirim. –

cevap

6

İki arasındaki fark, ikinci sürümün, sorgu yürütülürken tüm zaman için ThreadPool iş parçacığını engelleyeceğidir. Bu, bir GUI uygulamasında kabul edilebilir (tüm istediğiniz kod UI iş parçacığı dışında başka bir yerde yürütmek), ancak bir sunucu uygulamasında async'un ölçeklenebilirlik avantajlarını geçersiz kılar. Ayrıca

, ilk sürümü await her kullandığınızda sonra ConfigureAwait(false) kullanın (makul bir gereklilik olan) her gidiş dönüş için UI bağlama geri istemiyorsanız:

querySegment = await theQuery.AsTableQuery() 
          .ExecuteSegmentedAsync(…) 
          .ConfigureAwait(false); 

Bu şekilde, Birinciden sonraki tüm iterasyonlar (büyük ihtimalle) UI bağlamında değil, bir ThreadPool iş parçacığı üzerinde yürütülür.

BTW, ikinci versiyonda, aslında hiç de await gerekmez

, sadece doğrudan geri dönebilirler Task:

public Task<List<TAzureTableEntity>> GetByPartitionKey(string partitionKey) 
{ 
    return Task.Run(() => table.CreateQuery<TAzureTableEntity>() 
           .Where(ent => ent.PartitionKey == partitionKey) 
           .ToList()); 
} 
+0

querySegment (ilk sürüm) async'in ölçeklenebilirlik avantajlarını nasıl destekliyor? Her şey eşit olmakla birlikte hala bir ThreadPool iş parçacığı kullanıyorsunuz. Özellikle “ConfigureAwait (false)” kullanılırken. Doğru düşünüyor muyum? – Hallmanac

+1

@Hallmanac Hayır, bu yanlış. 'Bekleme' noktası, asenkron çalışma yürütülürken, herhangi bir iş parçacığını işgal etmediğinizdir. 'ConfigureAwait (false)' ile, bir sonraki parçayı başlatmak için sadece segmentler arasında kısa bir süre için bir 'ThreadPool' iş parçacığı kullanıyorsunuz. – svick

+2

Gotcha. "QuerySegment" için veri ile dönmek için beklerken bir "ThreadPool" iş parçacığı işgal ettiğini fark etmedi. İronik olarak, önceki yorumunuza daha derinden kazarken, bu konuda verdiğiniz iyi bir cevabı buldum. :-) Başkalarının bunu benim yaptığım kadar faydalı bulması durumunda bağlantı. http://stackoverflow.com/a/14898584/350312 – Hallmanac

2

Aradığınız cevabın bu olup olmadığından emin değilim ama yine de belirtmek istiyorum :).

Bildiğiniz gibi, 2. yöntem (Task kullanarak) dahili sembollerin dahili olarak ele alınmasını sağlar ve tüm varlıklar getirildiğinde yöntemden çıkar, 1. yöntem bir dizi öğe (en fazla 1000) alır. ve daha sonra sonuç kümesinin yanı sıra bir devam belirteci verir.

Tüm varlıkları bir tablodan almak ilginizi çekiyorsa, her iki yöntem de kullanılabilir; ancak bunlardan ilki, herhangi bir zamanda döngüden ayrılmanın esnekliğini size verir. Yani 1. işlevi kullanarak aslında sayfalandırma kavramını tanıtabilirsiniz.

Bir tablodan verileri gösteren bir web uygulaması oluşturduğunuzu varsayalım. Dahası, tablonun çok sayıda varlık içerdiğini varsayalım (100000 tüzel kişilik diyelim). 1. yöntemi kullanarak, 1000 öğeyi sonucu kullanıcıya döndürür ve kullanıcı isterse, sonraki 1000 öğe grubunu getirebilir ve kullanıcıya gösterebilirsiniz. Kullanıcının istediği zamana kadar bunu yapmaya devam edebilir ve tabloda veri var. 2. yöntemle, kullanıcı tüm 100000 varlığın tablodan alınmasını beklemek zorunda kalacaktı.

+0

Bunun hakkında düşündüğüm diğer sebep buydu. Eğer gerçek bir IEnumerable döndürme yöntemini kandırmak/zorlamak zorunda kalsaydım, async/await'in faydalarını reddederim. Sayfalama kullanım durumun biraz düşünmeme sebep oldu. Devam belirtecini tüketiciye iletmek zorunda kalacaksınız, böylece bıraktıkları yeri almak için depoya geri aktarabileceklerdir. Bu, bu bağlamda async için iyi bir kullanım durumu olurdu. – Hallmanac

İlgili konular