Vraag Entity Framework SaveChanges () versus SaveChangesAsync () en Find () versus FindAsync ()


Ik ben op zoek gegaan naar de verschillen tussen 2 paar hierboven, maar heb geen artikelen gevonden waarin duidelijk wordt uitgelegd en ook wanneer ik er een of andere moet gebruiken.

Dus wat is het verschil tussen SaveChanges() en SaveChangesAsync()?
En tussen Find() en FindAsync()?

Aan de serverkant, wanneer we gebruiken Async methoden, we moeten ook toevoegen await. Dus ik denk niet dat het asynchroon is aan de serverkant.

Helpt het alleen de UI-blokkering in de browser aan de clientzijde te voorkomen? Of zijn er voor- en nadelen tussen hen?


54
2018-05-05 01:26


oorsprong


antwoorden:


Elke keer dat u een actie moet uitvoeren op een externe server, genereert uw programma het verzoek, verzendt het en wacht u op een reactie. ik zal gebruiken SaveChanges() en SaveChangesAsync() als een voorbeeld, maar hetzelfde geldt voor Find() en FindAsync().

Stel dat je een lijst hebt myList van meer dan 100 items die u aan uw database moet toevoegen. Als u dat wilt invoegen, ziet uw functie er ongeveer zo uit:

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

Eerst maak je een instantie van MyEDM, voeg de lijst toe myList Naar de tafel MyTable, bel dan SaveChanges() om de wijzigingen in de database aan te houden. Het werkt zoals je wilt, de records worden gecommit, maar je programma kan niets anders doen totdat de commit is voltooid. Dit kan lang duren, afhankelijk van wat je doet. Als u wijzigingen aanbrengt in de records, moet de entiteit deze één voor één vastleggen (ik heb eens een save gehad van 2 minuten voor updates)!

Om dit probleem op te lossen, kunt u een van de twee dingen doen. De eerste is dat u een nieuwe thread kunt starten om de insert te verwerken. Terwijl dit de aanroepende draad vrijmaakt om door te gaan met het uitvoeren, hebt u een nieuwe thread gemaakt die daar gewoon gaat zitten wachten. Er is geen noodzaak voor die overhead, en dit is wat de async await patroon lost op.

Voor I / O-operaties, await wordt snel je beste vriend. Als we het codegedeelte van boven nemen, kunnen we het wijzigen om:

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

Het is een zeer kleine verandering, maar er zijn diepgaande effecten op de efficiëntie en prestaties van uw code. Dus wat gebeurt er? Het begin van de code is hetzelfde, u maakt een instantie van MyEDM en voeg uw toe myList naar MyTable. Maar als je belt await context.SaveChangesAsync(), de uitvoering van code keert terug naar de aanroepende functie! Dus terwijl u wacht totdat al die records vastleggen, kan uw code gewoon doorgaan met uitvoeren. Zeggen dat de functie die de bovenstaande code bevatte de handtekening had van public async Task SaveRecords(List<MyTable> saveList), de aanroepende functie kan er als volgt uitzien:

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");
}

Waarom je een functie als deze zou hebben, weet ik niet, maar wat deze uitvoert, laat zien hoe async await werken. Laten we eerst eens kijken wat er gebeurt.

Uitvoering komt binnen MyCallingFunction, Function Starting dan Save Starting wordt naar de console geschreven en vervolgens naar de functie SaveChangesAsync() wordt gebeld. Op dit punt keert de uitvoering terug naar MyCallingFunction en voert het voorloopschrift 'Continuing to Execute' tot 1000 keer in. Wanneer SaveChangesAsync() Fins, uitvoering keert terug naar de SaveRecordsfunctie, schrijven Save Complete naar de console. Als alles eenmaal binnen is SaveRecordsvoltooit, wordt de uitvoering voortgezet MyCallingFunction juist waar was het toen SaveChangesAsync() afgewerkt. Verward? Hier is een voorbeelduitvoer:

Functie starten
Begin opslaan
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
....
Doorgaan met uitvoeren!
Opslaan voltooid!
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
....
Doorgaan met uitvoeren!
Functie voltooid!

Of misschien:

Functie starten
Begin opslaan
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
Opslaan voltooid!
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
Doorgaan met uitvoeren!
....
Doorgaan met uitvoeren!
Functie voltooid!

Dat is het mooie van async await, uw code kan blijven lopen terwijl u wacht tot iets af is. In werkelijkheid zou je een functie meer als deze hebben als je roeping:

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());
}

Hier heb je vier verschillende opslagregistratie-functies tegelijkertijd. MyCallingFunction zal veel sneller voltooien met async await dan als individu SaveRecords functies werden in serie genoemd.

Het enige dat ik nog niet heb besproken, is het await trefwoord. Wat dit doet, is om de huidige functie te stoppen totdat alles is uitgevoerd Task je wacht op voltooiing. Dus in het geval van het origineel MyCallingFunction, de lijn Function Complete wordt pas in de console naar de console geschreven SaveRecords functie afwerkingen.

Lang verhaal kort, als je een optie hebt om te gebruiken async await, dat zou u moeten doen, aangezien het de prestaties van uw applicatie aanzienlijk zal verbeteren.


108
2018-05-05 02:33



Deze verklaring is onjuist:

Aan de serverkant moeten we ook await toevoegen wanneer we Async-methoden gebruiken.

U hoeft "wachten" niet toe te voegen. "wachten" is slechts een handig trefwoord in C # waarmee u meer regels code kunt schrijven na de aanroep, en die andere regels worden pas uitgevoerd nadat de bewerking Opslaan is voltooid. Maar zoals u al aangaf, kon u dat bereiken door simpelweg SaveChanges aan te roepen in plaats van SaveChangesAsync.

Maar fundamenteel, gaat een async vraag over veel meer dan dat. Het idee hier is dat als er ander werk is dat u kunt doen (op de server) terwijl de opslagbewerking bezig is, u SaveChangesAsync zou moeten gebruiken. Gebruik niet "wachten". Noem gewoon SaveChangesAsync en ga daarna door met andere dingen tegelijk te doen. Dit omvat mogelijk, in een webapp, het retourneren van een antwoord aan de klant zelfs voordat het opslaan is voltooid. Maar natuurlijk wil je nog steeds het uiteindelijke resultaat van de Save controleren, zodat in het geval dat het faalt, je dat aan je gebruiker kunt communiceren, of het op de een of andere manier kunt loggen.


3
2018-05-05 02:06