2015-05-19 3 views
0

Итак, это может быть глупый вопрос. Я не могу получить мою голову полностью вокруг ПОЧЕМУ с использованием EF6 Асинхронный улучшит производительность против оберточной синхронизации вызовов Ef6 в задаче (предположим, дБ звонки внутри метода Web API REST API)Async EF 6 vs wrapped Sync EF

Ie, почему это:

//wrapping synch with asynch 
return await Task.Run(() => 
{ 
    var albums = this.context.Albums 
       .Where(x => x.Artist.ID == artist.ID) 
       .ToList(); 
    return albums; 
}); 

хуже, чем это:

//using async 
return await this.context.Albums 
      .Where(x => x.Artist.ID == artist.ID) 
      .ToListAsync(); 

Примечание: Я есть прочитать эту статью http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx которая, кажется, говорят (упрощенно) «не просто обернуть SY несинхронный метод, перепишите метод более эффективно ».

Вопрос 1, это то, что сделала реализация асинхронного EF6? Я предполагаю, что использует асинхронный ввод-вывод в его реализации?

Вопрос 2 (и мой вопрос) - может кто-то объяснить, почему это лучше? Не приведет ли обе реализации к освобождению потока запросов для обработки других запросов до тех пор, пока операция db не будет выполнена?

ответ

5

Предположим, что вы готовите большой праздничный ужин. Там будет тонны еды, в том числе основное блюдо большой курицы. Это займет много времени, чтобы приготовить, поэтому вы готовите его и кладете в печь раньше, установите таймер, чтобы проверить его позже, а затем продолжайте готовить следующее блюдо (картофельное пюре).

Вы не можете просто сидеть и ждать (синхронно) для этой курицы до конца; вам нужно позволить ему готовить (асинхронно), пока вы отправляетесь на подготовку всех других блюд. Если вы ждали, когда курица закончит, прежде чем начинать работу над чем-либо еще, в дополнение к тому, что вам будет скучно, курица будет ледяной, когда вы закончите со всем остальным.

Теперь есть несколько способов сделать эту операцию (позволяя куриному повару) произойти, пока вы выполняете другую работу. Например, вы можете установить таймер и пойти проверить его, как только таймер уведомил вас, что время было. Другое решение - не работать самостоятельно. Вы могли бы схватить своего сына и сказать ему, чтобы он сидел перед плитой, ожидая, когда цыпленок будет готов, и сообщите ему, когда он будет готов.

Использование таймера аналогично однопоточному асинхронному решению. (Каждый человек является нитью.) Существует только один рабочий (вы), и вы начинаете асинхронную работу, асинхронные уведомления о том, когда вам нужно что-то делать, но только когда-либо работают над одной штукой одновременно. Наличие нескольких человек на кухне аналогично многопоточному приложению. Если вы используете эти несколько человек, чтобы на самом деле выполнять несколько задач, которые требуют, чтобы фактический человек выполнял работу в одно и то же время (например, вы месите картофель, пока ваш сын стирает спаржу), тогда вы выполняете свою работу Быстрее. Когда вы используете этого добавочного человека (нить), чтобы ничего не делать, кроме как сидеть и ждать, пока что-то закончится, пока вы идете на работу, тогда вы просто тратите время (поток) этого человека; им лучше уйти и сделать что-то продуктивное.

Чтобы полностью исключить аналогию, когда вы используете Task.Run для выполнения IO синхронно, вы планируете работать в пуле потоков, где выделенный поток должен просто сидеть там, ничего не делая (вместо выполнения фактической продуктивной работы), пока он ждет завершения ввода-вывода. Когда вы просто используете по существу асинхронные операции ввода-вывода, то не задействованы никакие другие потоки на всех.

+0

Очень хорошая аналогия. – juharr

+0

Спасибо за ваш ответ и аналогию. Имеет смысл. Как точно, являются ли методы Async EF6 (ToListAsync) * неотъемлемо * async? Это потому, что они используют асинхронный ввод-вывод в своей реализации? – HokieMike

+0

@HokieMike Да. IO по своей природе практически всегда асинхронно. Практически каждый раз, когда вы видите синхронные методы ввода-вывода, это означает, что что-то, где-то, * выходит из своего пути *, чтобы синхронно блокировать до тех пор, пока асинхронное уведомление не сообщит, что оно может продолжаться. Многие API-интерфейсы операций ввода-вывода выходят из своего пути, чтобы скрыть присущую им асинхронность; но теперь становится все более распространенным в C#, чтобы фактически разоблачить эту асинхронность вызывающего. – Servy

Смежные вопросы