2015-05-05 18 views
49

Yukarıdaki 2 çift arasındaki farkları araştırıyorum, ancak ne zaman kullanılacağı ile ilgili net bir şekilde açıklayan herhangi bir makale bulamadım biri ya da başka bir tanesi.Varlık Çerçevesi SaveChanges() vs. SaveChangesAsync() ve Find() vs. FindAsync()

SaveChanges() ve SaveChangesAsync() arasındaki fark nedir?
Ve Find() ve FindAsync() arasında?

Sunucu tarafında, Async yöntemlerini kullandığımızda, await'u da eklememiz gerekir. Bu nedenle, sunucu tarafında asenkron olduğunu düşünmüyorum.

Yalnızca istemci tarafındaki tarayıcıda UI engellemesinin engellenmesine yardımcı oluyor mu? Yoksa aralarında artıları ve eksileri var mı?

+1

zaman uyumsuz fazla, * çok * istemci uygulamalarında engellemesini istemci UI iş parçacığı durdurma daha fazla. Eminim yakında gelen bir uzman cevabı var. – jdphenix

cevap

98

Uzak bir sunucuda işlem yapmanız gereken her zaman, program isteğinizi oluşturur, gönderir, sonra yanıt bekler. Örnek olarak SaveChanges() ve SaveChangesAsync() kullanacağım, ancak aynı Find() ve FindAsync() için geçerlidir.

Veritabanınıza eklemeniz gereken 100 + öğeden oluşan bir listenin myList olduğunu varsayalım. veritabanına değişiklikleri devam etmek SaveChanges() çağrı sonra, masanın MyTable listeyi myList ekleyin MyEDM ait

using(var context = new MyEDM()) 
{ 
    context.MyTable.AddRange(myList); 
    context.SaveChanges(); 
} 

Öncelikle oluşturmak ve örnek: O eklemek için, fonksiyon şöyle görünecektir. İstediğiniz gibi çalışır, kayıtlar işe alınır, ancak programınız taahhüt tamamlanana kadar başka bir şey yapamaz. Bu, ne yaptığınıza bağlı olarak uzun zaman alabilir. Kayıtlarda değişiklik yapmakla yükümlü olursanız, tarafın bunları bir seferde yerine getirmesi gerekir (Bir kez bir kez kaydetme güncellemeleri için 2 dakika sürdüm)!

Bu sorunu çözmek için iki şeyden birini yapabilirsiniz. İlk olarak, eki işlemek için yeni bir iş parçacığı başlatabilirsiniz. Bu, yürütmeye devam etmek için çağrı iş parçacığını serbest bırakacak olsa da, yalnızca orada oturup bekleyeceğiniz yeni bir iş parçacığı oluşturdunuz. Bu yüke gerek yok ve bu async await modelinin çözdüğü şey.

I/O karşıtları için, await hızlı bir şekilde en iyi arkadaşınız olur.

using(var context = new MyEDM()) 
{ 
    Console.WriteLine("Save Starting"); 
    context.MyTable.AddRange(myList); 
    await context.SaveChangesAsync(); 
    Console.WriteLine("Save Complete"); 
} 

Çok küçük bir değişiklik, ancak kod verimliliği ve performansı üzerinde derin etkileri vardır: Yukarıdaki kod bölümünü alarak, biz olmak değiştirebilir. Peki ne olur? kodun başlangıcı Eğer MyEDM bir örneğini oluşturmak ve sizin myListMyTable eklemek aynıdır. Ancak, await context.SaveChangesAsync()'u aradığınızda, kodunun yürütülmesi çağıran işleve geri döner! Bu kayıtların tamamlanmasını beklerken, kodunuz çalışmaya devam edebilir. Eğer böyle bir işlevi olurdu Neden

public async Task MyCallingFunction() 
{ 
    Console.WriteLine("Function Starting"); 
    Task saveTask = SaveRecords(GenerateNewRecords()); 

    for(int i = 0; i < 1000; i++){ 
     Console.WriteLine("Continuing to execute!"); 
    } 

    await saveTask; 
    Console.Log("Function Complete"); 
} 

, bilmiyorum, ama bu gösterileri nasıl verir neyi: Yukarıdaki kod public async Task SaveRecords(List<MyTable> saveList) imzasını vardı içeriyordu işlevini Say, çağıran işlevi aşağıdaki gibi görünebilir async await çalışır. Önce olanları gözden geçirelim.

Yürütme işlemi MyCallingFunction, Function Starting girer ve Save Starting konsoluna yazılır, daha sonra SaveChangesAsync() işlevi çağrılır. Bu noktada, yürütme MyCallingFunction'a döner ve 'Dönmeye Devam Ediyor' for döngüsü için 1000 defaya kadar girer. SaveChangesAsync() finiş olduğunda, yürütmeişlevine geri döner ve Save Complete konsoluna yazılır. SaveRecords tamamlanıncaya her şeyi sonra, yürütme hakkı SaveChangesAsync() bittiğinde öyleydi idi MyCallingFunction devam edecektir. Şaşkın?

 
Function Starting 
Save Starting 
Continuing to execute! 
Continuing to execute! 
Continuing to execute! 
Continuing to execute! 
Continuing to execute! 
.... 
Continuing to execute! 
Save Complete! 
Continuing to execute! 
Continuing to execute! 
Continuing to execute! 
.... 
Continuing to execute! 
Function Complete! 

Ya da belki: İşte bir örnek çıkışı

async await güzelliği, kodunuz bitirmek için bir şey beklerken çalışmaya devam edebilir olduğunu
 
Function Starting 
Save Starting 
Continuing to execute! 
Continuing to execute! 
Save Complete! 
Continuing to execute! 
Continuing to execute! 
Continuing to execute! 
.... 
Continuing to execute! 
Function Complete! 

. Gerçekte, kendi çağıran fonksiyonu olarak bir işlev daha böyle olurdu:

public async Task MyCallingFunction() 
{ 
    List<Task> myTasks = new List<Task>(); 
    myTasks.Add(SaveRecords(GenerateNewRecords())); 
    myTasks.Add(SaveRecords2(GenerateNewRecords2())); 
    myTasks.Add(SaveRecords3(GenerateNewRecords3())); 
    myTasks.Add(SaveRecords4(GenerateNewRecords4())); 

    await Task.WhenAll(myTasks.ToArray()); 
} 

Burada, aynı zamanda de gidiş dört farklı kaydetmek rekor fonksiyonlara sahiptir. async await kullanarak MyCallingFunction çok daha hızlı tamamlayacak, daha sonra bireysel SaveRecords fonksiyonları seri olarak çağrıldı.

Henüz üzerinde dokunmadım bir şey await anahtar kelimedir. Bu, mevcut fonksiyonun tamamlanmasını bekleyen Task ne kadar devam etmesini engeller. SaveRecords fonksiyonu bitene kadar orijinal MyCallingFunction durumunda Yani, hat Function Complete konsola yazılır edilmeyecektir. Eğer async await kullanmak için bir seçenek varsa

Uzun lafın kısası, bunu büyük ölçüde uygulama performansını artıracaktır gerektiği gibi.

+3

çok güzel bir açıklama, teşekkürler! – renakre

+3

Zamanın% 99'u hala devam edebilmem için veri tabanından değerler alınmasını beklemek zorundayım. Hala uyumsuz kullanmalı mıyım? Eşzamansız 100 kişiyi web siteme eşzamansız olarak bağlamaya izin veriyor mu? Eğer uyumsuzluğu kullanmazsam, bu 100 kullanıcının tümünde bir defada 1. satırda beklemesi gerektiği anlamına mı geliyor? – MIKE

+1

Değer belirleme: İş parçacığı havuzundan yeni bir iş parçacığı oluşturmak, ASP'yi temel olarak ASP'den (yani iş parçacığının diğer istekleri karşılayamadığı veya engelleme çağrısında kaldığı için herhangi bir şey yapamayacağı anlamına gelen) bir ASP'yi üzgün bir panda haline getirir. Ancak, “bekle” yi kullanırsanız, SaveChanges çağrısından sonra başka bir şey yapmanıza gerek kalmasa bile, ASP “aha, bu iş parçacığı bir async işlemi beklerken geri döndü demektir, bu, bu iş parçacığının başka bir istekte bulunmasına izin verebilirim anlamına gelir. bu arada!" Bu, uygulama ölçeğinizi yatay olarak çok daha iyi hale getirir. – kai

3

Bu ifade yanlıştır: Biz zaman uyumsuz yöntemleri kullanırken

Sunucu tarafında

, biz de beklemektedir eklemeniz gerekir.

"Beklemeyi" eklemeniz gerekmez. "beklemek" sadece C# 'den gelen ve aramadan sonra daha fazla kod yazmanıza olanak veren kullanışlı bir anahtar kelimedir ve diğer satırlar yalnızca Kaydetme işlemi tamamlandıktan sonra çalıştırılacaktır. Ancak, belirttiğiniz gibi, bunu SaveChangesAsync yerine SaveChanges çağırarak gerçekleştirebilirsiniz. Temel olarak, bir async çağrısı bundan çok daha fazlasıdır. Buradaki fikir şudur: Eğer başka bir iş varsa, Kaydetme işlemi devam ederken (sunucuda) yapabilirsiniz, o zaman SaveChangesAsync kullanmalısınız. "Beklemeyin" kullanmayın. SaveChangesAsync'i çağırın ve sonra başka şeyleri paralel olarak yapmaya devam edin. Bu, bir web uygulamasında potansiyel olarak, Kaydetme tamamlanmadan önce müşteriye bir yanıt döndürmeyi içerir. Ama elbette, yine de Kaydet'in son sonucunu kontrol etmek isteyeceksiniz, böylece başarısız olursa, bunu kullanıcıya iletebilir veya bir şekilde günlüğe kaydedebilirsiniz.

+3

Aslında bu aramaları beklemek istersiniz, aksi halde aynı DbContext örneğini kullanarak sorguları çalıştırabilir veya verileri eşzamanlı olarak kaydedebilir ve DbContext iş parçacığı için güvenli değildir. Bunun üstünde, istisnaları halletmeyi kolaylaştırır. Beklemeden görevi saklamak ve hata olup olmadığını kontrol etmek zorundasınız, ancak ne zaman tamamlandığını bilmeden, ne zaman beklediğinizden çok daha fazla düşünmeyi gerektiren '.ContinueWith' seçeneğini kullanmazsanız ne zaman kontrol edeceğinizi bilmezsiniz. – Pawel

+14

Bu cevap aldatıcıdır, beklemeden bir async yönteminin çağrılması onu "ateş ve unut" yapar."Metot söner ve muhtemelen bir süre sonra tamamlanacaktır, ama asla ve ne zaman bilemeyeceğiniz bir istisna atarsınız, bunu asla duymayacaksınız, onun tamamlanması ile senkronize edemezsiniz. Bu tür tehlikeli bir davranış seçilmelidir, "istemcideki beklemeler, sunucuda bekletme yok" gibi basit (ve yanlış) bir kuralla çağrılmadı. –

+1

Bu, belgelerinde okudum ama gerçekten dikkate almadığım çok yararlı bir bilgidir. seçenek: 1. John Melville gibi "Fire and unutma" için "SaveChangesAsync()" deyiniz ... bazı durumlarda bana yararlı olan ... 2. "Kaydet, arayan kişiye geri dön ve kaydet" Daha sonra kaydetme tamamlandıktan sonra bazı 'post-save' kodunu yürütün. Çok kullanışlı bir parça. Teşekkür ederim. –