Использование ожидаемых [асинхронных задач] на разных уровнях архитектуры C # - PullRequest
0 голосов
/ 20 мая 2019

Я уже несколько дней пытаюсь проверить, где ждать, а где нет.

У меня есть класс репозитория, который выбирает данные из базы данных. используя EntityFramework код будет выглядеть примерно так:

public async Task<List<Object>> GetAsync()
{
  return await context.Set<Object>().ToListAsync();
}

и потребитель:

var data = await GetAsync();

и на верхнем уровне я тоже жду этого метода. я должен использовать await только для одного из этих методов? Это снижение производительности при использовании ресурсов и создание нового потока каждый раз, когда вы ожидаете?

Я проверил вопросы, перечисленные в комментариях, и они не относятся к проблемам с производительностью и просто говорят, что вы можете это сделать. Я хотел получить лучшую практику и причину, по которой этого нельзя делать.

Ответы [ 2 ]

1 голос
/ 20 мая 2019

Я бы хотел добавить к этому. В некоторых async методах нет необходимости использовать async/await ключевые слова. Обнаружение такого неправильного использования важно, потому что добавление модификатора async имеет свою цену.

например. Вам не нужно async/await ключевых слов в вашем примере.

public Task<List<Object>> GetAsync()
{
  return context.Set<Object>().ToListAsync();
}

А потом:

var data = await GetAsync();

Будет просто отлично. В этом случае вы возвращаете Task<List<Object>>, а затем ожидаете, что там, где вы непосредственно работаете с объектами.

Я рекомендую установить async await helper

0 голосов
/ 20 мая 2019

Позвольте мне сначала понять суть вашего вопроса, путаница связана с , где использовать Async в полной цепочке вызовов, а где нет и , как оценить влияние использования на производительность , так как это может привести к созданию большего количества потоков. Если синопсис выходит за рамки этого, добавьте детали к комментариям, я пока попытаюсь ответить на них.

Давайте разделим и разберем каждого из них по одному.

Где использовать Async в цепочке вызовов, а где нет?

  • Здесь, когда вы используете Entity Framework для доступа к базе данных, я могу с уверенностью предположить, что вы используете асинхронную обработку на основе ввода-вывода, которая является наиболее заметным вариантом использования для асинхронной обработки в разных языках и средах, примеры использования для асинхронной обработки на основе ЦП: относительно ограничен (объясню их тоже)
  • Async - это функция масштабируемости, особенно для обработки ввода-вывода, а не для повышения производительности. Проще говоря, с помощью асинхронной обработки вы можете гарантировать, что размещенный сервер может обслуживать во много раз больше вызовов для обработки ввода-вывода, поскольку вызовы не блокируются и они просто передаются вручную. через запрос обработки по сети, в то время как поток процесса возвращается в пул, готовый обработать другой запрос, завершая передачу процесса за несколько миллисекунд
  • Когда обработка завершена, программный поток должен просто принять их и передать обратно клиенту, опять же, через несколько миллисекунд, в основном это около <1 мс, если это чистый проход без логического вызова IO </li>

Какие преимущества

  • Представьте, что вместо этого вы делаете синхронный вызов ввода-вывода в базу данных, где каждый задействованный поток будет просто ждать получения результата, который может пройти через несколько секунд, влияние будет крайне отрицательным, в целом, в зависимости от размера пула потоков, вы можете сервер Максимум 25 - 50 запросов, и они тоже ответят о количестве ядер, доступных для обработки, будут постоянно тратить ресурсы впустую, пока они простаивают и ожидают ответа
  • Если вы делаете синхронный вызов, то невозможно выполнить более 1000 запросов в одной и той же настройке, и я очень консервативен. Async может оказать огромное влияние на масштабируемость, тогда как для облегченных вызовов он может легко обслуживать миллионы запросов из одного размещенного процесса

После фона, где использовать Async в полной цепочке

  • Везде , выполнимо от начала до конца, от точки входа до фактической точки выхода, выполняющей вызов IO, поскольку это фактический вызов, освобождающий поток пула, поскольку он отправляет вызов по сети
  • Запомните, хотя , await в данной точке не позволяют дальнейшему коду обрабатывать модули одного и того же метода, даже если он освобождает поток, поэтому лучше, если существует несколько независимых вызовов, они агрегируются с использованием Task.WhenAll, и ожидается репрезентативная задача, которая вернется, когда все они завершат успех / ошибку, что когда-либо может быть состоянием
  • Если между асинхронным прерыванием используется что-то вроде Task.Wait или Task.Result, он не останется чистым асинхронным вызовом и заблокирует поток пула вызывающих потоков

Как можно улучшить Async?

  • В вызовах библиотеки Pure, когда Async инициируется пулом потоков, а поток диспетчеризации может отличаться от получаемого, и вызову не нужно повторно вводить тот же контекст, вы должны использовать ConfigureAwait(false), что означает, что он не будет ждать повторно войти в исходный контекст и повышение производительности
  • Как и await имеет смысл использовать ConfigureAwait(false) через цепочку, вход в конец. Это действительно только для библиотек, которые широко отвечают на пулы потоков

Есть ли созданная тема

  • Лучше прочитайте это, Стивен Клири - Нет темы
  • Подлинный асинхронный вызов ввода-вывода будет использовать аппаратный параллелизм для обработки, не будет блокировать Программные Потоки

Изменения

  • Асинхронная обработка на базе процессора, где вы берете вещи в фоновом режиме, поскольку текущий поток должен быть отзывчивым, в основном в случае Ui, например WPF

Примеры использования

  • Все виды систем, особенно не-MS Framework, такие как узел js, имеют асинхронную обработку в качестве базового принципа, и кластер сервера базы данных на принимающей стороне настроен на получение миллионов вызовов и их обработку
  • B2C вызовыОжидается, что каждый запрос является легковесным с ограниченной полезной нагрузкой

Редактировать 1:

Только в этом конкретном случае, как указано здесь , ToListAsync по умолчанию является асинхронным, поэтому в этом случае вы можете пропустить асинхронное ожидание, как указано в комментариях к вариопусу, хотя в общем случае ознакомьтесь со статьей Стефана Клили, которая может быть не очень хорошей стратегией, поскольку выгоды минимальны и негативное влияние на неправильностьиспользование может быть высоким

...