Asynchronní dotaz a uložení
Poznámka:
Pouze EF6 a novější – Funkce, rozhraní API atd. popsané na této stránce byly představeny v Entity Framework 6. Pokud používáte starší verzi, některé nebo všechny informace nemusí být platné.
EF6 zavedl podporu asynchronního dotazu a uložení pomocí asynchronních a await klíčových slov , která byla zavedena v .NET 4.5. I když ne všechny aplikace můžou využívat asynchronní synchronizaci, je možné ji použít ke zlepšení odezvy klienta a škálovatelnosti serveru při zpracování dlouhotrvajících úloh, sítí nebo vstupně-výstupních úloh.
Kdy opravdu používat asynchronní
Účelem tohoto názorného postupu je zavést asynchronní koncepty způsobem, který usnadňuje sledování rozdílu mezi asynchronním a synchronním spuštěním programu. Tento názorný postup není určen k ilustraci žádného z klíčových scénářů, ve kterých asynchronní programování poskytuje výhody.
Asynchronní programování se primárně zaměřuje na uvolnění aktuálního spravovaného vlákna (vlákno s kódem .NET), aby fungovalo jinak, zatímco čeká na operaci, která nevyžaduje žádný výpočetní čas ze spravovaného vlákna. Zatímco například databázový stroj zpracovává dotaz, kód .NET nic dělat není.
V klientských aplikacích (WinForms, WPF atd.) lze aktuální vlákno použít k zachování odezvy uživatelského rozhraní při provedení asynchronní operace. V serverových aplikacích (ASP.NET atd.) lze vlákno použít ke zpracování jiných příchozích požadavků – to může snížit využití paměti nebo zvýšit propustnost serveru.
Ve většině aplikací používajících async nebude mít žádné znatelné výhody a dokonce může být škodlivé. Před potvrzením použití testů, profilace a běžného rozumu změřte dopad asynchronní synchronizace ve vašem konkrétním scénáři.
Tady je několik dalších zdrojů informací o asynchronním použití:
- Brandon Bray přehled async/await v .NET 4.5
- Asynchronní programovací stránky v knihovně MSDN
Vytvoření modelu
K vytvoření modelu a vygenerování databáze použijeme pracovní postup Code First, ale asynchronní funkce budou fungovat se všemi modely EF, včetně modelů vytvořených pomocí nástroje EF Designer.
- Vytvoření konzolové aplikace a jeho volání AsyncDemo
- Přidání balíčku NuGet EntityFramework
- V Průzkumník řešení klikněte pravým tlačítkem na projekt AsyncDemo.
- Vyberte Spravovat balíčky NuGet...
- V dialogovém okně Spravovat balíčky NuGet vyberte kartu Online a zvolte balíček EntityFramework .
- Klikněte na Nainstalovat.
- Přidejte třídu Model.cs s následující implementací.
using System.Collections.Generic;
using System.Data.Entity;
namespace AsyncDemo
{
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public virtual List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; }
}
}
Vytvoření synchronního programu
Teď, když máme model EF, napište kód, který ho používá k provádění přístupu k datům.
- Obsah souboru Program.cs nahraďte následujícím kódem.
using System;
using System.Linq;
namespace AsyncDemo
{
class Program
{
static void Main(string[] args)
{
PerformDatabaseOperations();
Console.WriteLine("Quote of the day");
Console.WriteLine(" Don't worry about the world coming to an end today... ");
Console.WriteLine(" It's already tomorrow in Australia.");
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
public static void PerformDatabaseOperations()
{
using (var db = new BloggingContext())
{
// Create a new blog and save it
db.Blogs.Add(new Blog
{
Name = "Test Blog #" + (db.Blogs.Count() + 1)
});
Console.WriteLine("Calling SaveChanges.");
db.SaveChanges();
Console.WriteLine("SaveChanges completed.");
// Query for all blogs ordered by name
Console.WriteLine("Executing query.");
var blogs = (from b in db.Blogs
orderby b.Name
select b).ToList();
// Write all blogs out to Console
Console.WriteLine("Query completed with following results:");
foreach (var blog in blogs)
{
Console.WriteLine(" " + blog.Name);
}
}
}
}
}
Tento kód volá metoduPerformDatabaseOperations
, která uloží nový blog do databáze a pak načte všechny blogy z databáze a vytiskne je do konzoly. Potom program napíše citát dne do konzoly.
Vzhledem k tomu, že kód je synchronní, můžeme při spuštění programu sledovat následující tok spuštění:
SaveChanges
začne odesílat nový blog do databáze.SaveChanges
Dokončí- Dotaz na všechny blogy se odešle do databáze.
- Vrácení dotazu a výsledky se zapisují do konzoly.
- Citace dne se zapíše do konzoly.
Vytvoření asynchronního
Teď, když máme náš program spuštěný, můžeme začít používat nové asynchronní a await klíčová slova. Provedli jsme následující změny souboru Program.cs.
- Řádek 2: Příkaz using pro
System.Data.Entity
obor názvů nám poskytuje přístup k asynchronním rozšiřujícím metodám EF. - Řádek 4: Příkaz using pro
System.Threading.Tasks
obor názvů nám umožňuje použítTask
typ. - Řádek 12 a 18: Zaznamenáváme jako úkol, který sleduje průběh
PerformSomeDatabaseOperations
(řádek 12) a pak blokuje provádění programu pro tento úkol, jakmile se dokončí všechna práce programu (řádek 18). - Řádek 25: Aktualizovali jsme, abychom byli označeni jako
async
a vrátiliPerformSomeDatabaseOperations
hodnotuTask
. - Řádek 35: Nyní voláme asynchronní verzi
SaveChanges
a čekáme na dokončení. - Řádek 42: Nyní voláme asynchronní verzi
ToList
a čekáme na výsledek.
Úplný seznam dostupných rozšiřujících metod v System.Data.Entity
oboru názvů najdete ve QueryableExtensions
třídě. Budete také muset přidat using System.Data.Entity
do příkazů using.
using System;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
namespace AsyncDemo
{
class Program
{
static void Main(string[] args)
{
var task = PerformDatabaseOperations();
Console.WriteLine("Quote of the day");
Console.WriteLine(" Don't worry about the world coming to an end today... ");
Console.WriteLine(" It's already tomorrow in Australia.");
task.Wait();
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
public static async Task PerformDatabaseOperations()
{
using (var db = new BloggingContext())
{
// Create a new blog and save it
db.Blogs.Add(new Blog
{
Name = "Test Blog #" + (db.Blogs.Count() + 1)
});
Console.WriteLine("Calling SaveChanges.");
await db.SaveChangesAsync();
Console.WriteLine("SaveChanges completed.");
// Query for all blogs ordered by name
Console.WriteLine("Executing query.");
var blogs = await (from b in db.Blogs
orderby b.Name
select b).ToListAsync();
// Write all blogs out to Console
Console.WriteLine("Query completed with following results:");
foreach (var blog in blogs)
{
Console.WriteLine(" - " + blog.Name);
}
}
}
}
}
Teď, když je kód asynchronní, můžeme při spuštění programu sledovat jiný tok provádění:
SaveChanges
začne odesílat nový blog do databáze.
Jakmile se příkaz odešle do databáze, není potřeba žádný další výpočetní čas v aktuálním spravovaném vlákně. MetodaPerformDatabaseOperations
se vrátí (i když se nedokončila provádění) a tok programu v metodě Main pokračuje.- Citace dne se zapíše do konzoly.
Vzhledem k tomu, že v metodě Main není k dispozici žádná další práce, spravované vlákno je blokováno voláníWait
, dokud se operace databáze nedokončí. Po dokončení se provede zbytek našíPerformDatabaseOperations
operace. SaveChanges
Dokončí- Dotaz na všechny blogy se odešle do databáze.
Spravované vlákno je opět možné provádět jiné práce, zatímco dotaz je zpracován v databázi. Vzhledem k tomu, že se dokončilo všechna ostatní spuštění, vlákno se ale zastaví při volání Wait. - Vrácení dotazu a výsledky se zapisují do konzoly.
Vysuďte si to.
Viděli jsme, jak snadné je používat asynchronní metody EF. I když u jednoduché konzolové aplikace nemusí být výhody asynchronního přístupu úplně zřejmé, můžete použít stejné strategie v situacích, kdy dlouhotrvající nebo síťové aktivity můžou aplikaci jinak blokovat nebo způsobit, že velký počet vláken zvýší nároky na paměť.