Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Замечание
EF6 и более поздние версии — функции, API и т. д., рассмотренные на этой странице, были представлены в Entity Framework 6. Если вы используете более раннюю версию, некоторые или все сведения не применяются.
EF6 представила поддержку асинхронных запросов и сохранения с использованием ключевых слов async и await, которые были введены в .NET 4.5. Хотя не все приложения могут выиграть от асинхронного подхода, его можно использовать для повышения отзывчивости клиентов и масштабируемости сервера при обработке длительных, сетевых или операций ввода-вывода задач.
Когда действительно использовать async
Цель этого пошагового руководства — ввести асинхронные понятия таким образом, чтобы было легко наблюдать разницу между асинхронным и синхронным выполнением программы. Это пошаговое руководство не предназначено для иллюстрации любого из ключевых сценариев, в которых асинхронное программирование обеспечивает преимущества.
Асинхронное программирование в основном сосредоточено на освобождении текущего управляемого потока (поток под управлением кода .NET) для выполнения другой работы во время ожидания операции, которая не требует времени вычислений из управляемого потока. Например, в то время как ядро СУБД обрабатывает запрос, не требуется ничего делать с помощью кода .NET.
В клиентских приложениях (WinForms, WPF и т. д.) текущий поток можно использовать для реагирования пользовательского интерфейса при выполнении асинхронной операции. В серверных приложениях (ASP.NET и т. д.) поток можно использовать для обработки других входящих запросов. Это может снизить использование памяти и /или увеличить пропускную способность сервера.
В большинстве приложений, использующих асинхронный код, не будет заметных преимуществ и даже может быть вредным. Используйте тесты, профилирование и здравый смысл, чтобы оценить влияние асинхронности в вашей конкретной ситуации, прежде чем принимать решение о её использовании.
Ниже приведены дополнительные ресурсы для получения сведений об асинхронном коде:
- Обзор Брэндона Брэя по асинхронному программированию и await в .NET 4.5
- Страницы асинхронного программирования в библиотеке MSDN
Создание модели
Мы будем использовать рабочий процесс Code First для создания модели и создания базы данных, однако асинхронная функциональность будет работать со всеми моделями EF, включая созданные с помощью конструктора EF.
- Создание консольного приложения и вызов asyncDemo
- Добавление пакета NuGet EntityFramework
- В обозревателе решений щелкните правой кнопкой мыши проект AsyncDemo
- Выберите "Управление пакетами NuGet...
- В диалоговом окне "Управление пакетами NuGet" выберите вкладку "Интернет" и выберите пакет EntityFramework
- Щелкните Установить.
- Добавление класса Model.cs со следующей реализацией
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; }
}
}
Создание синхронной программы
Теперь, когда у нас есть модель EF, давайте напишите код, который использует его для выполнения доступа к данным.
- Замените содержимое Program.cs следующим кодом.
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);
}
}
}
}
}
Этот код вызывает PerformDatabaseOperations метод, который сохраняет новый блог в базе данных, а затем извлекает все блоги из базы данных и выводит их в консоль. После этого программа записывает цитату дня в консоль.
Так как код синхронен, при запуске программы можно наблюдать следующий поток выполнения:
-
SaveChangesначинает отправлять новый блог в базу данных -
SaveChangesЗавершает - Запрос ко всем блогам отправляется в базу данных
- Возвращаемые запросы и результаты записываются в консоль
- Цитата дня записывается в консоль
Сделать его асинхронным
Теперь, когда наша программа запущена и работает, мы можем начать использовать новые ключевые слова async и await. Мы внесли следующие изменения в Program.cs
- Строка 2. Оператор using для пространства имен
System.Data.Entityпредоставляет нам доступ к асинхронным методам расширения EF. - Строка 4. Оператор using для пространства имен
System.Threading.Tasksпозволяет использовать типTask. - Строка 12 и 18. Мы создаем задачу, которая отслеживает ход выполнения
PerformSomeDatabaseOperations(строка 12), а затем блокируем выполнение программы до завершения этой задачи после того, как вся работа программы выполнена (строка 18). - Строка 25: Мы обновили
PerformSomeDatabaseOperations, чтобы было помечено какasyncи возвращалоTask. - Строка 35: Мы теперь вызываем асинхронную версию
SaveChangesи ожидаем её завершения. - На строке 42 мы теперь вызываем асинхронную версию метода
ToListи ожидаем результата.
Полный список доступных методов расширения в System.Data.Entity пространстве имен см. в QueryableExtensions классе.
Вам также потребуется добавить using System.Data.Entity в директивы 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);
}
}
}
}
}
Теперь, когда код является асинхронным, мы можем наблюдать другой поток выполнения при запуске программы:
-
SaveChangesначинает отправлять новый блог в базу данных
После отправки команды в базу данных не требуется больше времени вычислений в текущем управляемом потоке. МетодPerformDatabaseOperationsвозвращает (даже если он не завершил выполнение) и поток программы в методе Main продолжается. -
Цитата дня записывается в консоль
Так как в методе Main больше нет никаких действий, управляемый поток блокируется при вызовеWaitдо завершения операции базы данных. Завершив его, оставшаяся часть будетPerformDatabaseOperationsвыполнена. -
SaveChangesЗавершает - Запрос ко всем блогам отправляется в базу данных
Опять же, управляемый поток может выполнять другие действия во время обработки запроса в базе данных. Поскольку все остальные выполнения завершены, поток, тем не менее, просто остановится на вызове "Wait". - Возвращаемые запросы и результаты записываются в консоль
Основной вывод
Теперь мы узнали, насколько легко использовать асинхронные методы EF. Хотя преимущества асинхронного кода могут быть не очень очевидными в простом консольном приложении, эти же стратегии могут применяться в ситуациях, когда действия с длительным временем выполнения или использующие сеть в противном случае могут заблокировать приложение или привести к увеличению числа потоков, увеличивая использование памяти.