Писать асинхронную версию процедуры имеет смысл только в том случае, если в версии синхронизации имеется ожидание в режиме ожидания, обычно ожидание завершения другого процесса, например, ожидание открытия файла или результатов запроса к базе данных. или некоторая информация из Интернета.
Метод синхронизации просто бездействует, ожидая завершения другого процесса, блокируя, таким образом, выполнение вашей программы. В методе async-await поток просматривает, может ли он сделать что-то еще вместо ожидания ожидания.
Это легче всего понять, если сравнить это с поваром, готовящим завтрак, как описано в это интервью с Эриком Липпертом . Найдите где-то посередине асинхронное ожидание.
Если повар должен делать завтрак синхронно, он начнет кипятить воду, подождать, пока вода не закипит, использовать кипящую воду, чтобы приготовить чай, начать поджаривать хлеб, подождать, покахлеб поджаривают, начинают варить яйца, ждут, пока яйца не закипят, и т. д. Вы увидите все ожидания ожидания.
Асинхронный повар начнет кипятить воду, но вместо того, чтобы ждатьвода до кипения, он начал бы поджаривать хлеб и кипящую воду. Хотя ему приходится ждать завершения этих процессов, он может вместо этого делать что-то еще, например, нарезать помидоры. Через некоторое время вода для чая закипела. Он заваривает чай и продолжает работать, пока хлеб не будет поджарен и т. Д. Пока есть работа, повар не будет бездельничать, а будет делать то, что может, без результатов заданий, которые он начал.
Вернуться к вашему вопросу
Если процедуре не нужно ждать завершения какого-либо другого процесса, создавать для нее асинхронную версию не имеет смысла. Если процедура занимает значительное время, позвольте вашему абоненту решить, нужно ли ему реагировать, и запустите задачу, которая вызывает вашу функцию.
Другая причина - реализация интерфейса. Это может быть причиной не создания одного интерфейса с версиями sync и async, а двумя интерфейсами: один с функциями синхронизации и один с функциями асинхронности. Классы с функциями, которым не нужно ждать без дела, будут реализовывать только синхронизированную версию интерфейса.
Если у вас есть класс с двумя методами, которые имеют одинаковую функциональность, единственное отличие состоит в том, что один является асинхронным,а другой нет, рассмотрите возможность разбивать метод на подметоды и создавать асинхронные версии только тогда, когда вы можете вызвать асинхронную функцию:
IEnumerable<int> ReadNumbers(string fileName1)
{
// Read File 1, wait idly,
string text1 = ReadTextFile(fileName1);
// convert the read texts to numbers, and return in ascending order
IEnumerable<int> result = ConvertToAscendingInt(text1);
return result;
}
Этот метод ожидает в режиме ожидания при чтении текстового файла. Чтобы предотвратить это, вызовите асинхронную версию. Все остальные вещи не являются бездействующими, нет необходимости в асинхронной версии:
async Task<IEnumerable<int>> ReadNumbersAsync(string fileName1)
{
// Start reading File 1 async
string text1 = await ReadTextFileAsync(fileName1);
// convert the read texts to numbers, and return in ascending order
IEnumerable<int> result = ConvertToAscendingInt(text1);
return result;
}
Таким образом, большая часть кода будет в подметодах. Легче видеть, что методы sync и async делают одно и то же. Если в будущем преобразование будет выполнено по-другому, оно будет выполнено автоматически как для синхронизации, так и для асинхронной версии.
Наконец, вы можете разрешить версии синхронизации вызывать асинхронную версию. Затраты на выполнение задачи замедляют синхронизацию:
IEnumerable<int> ReadNumbers(string fileName1)
{
var taskReadNumbers = Task.Run( () => ReadNumbersAsync(fileName1);
taskReadNumbers.Wait();
return taskReadNumbers.Result();
}
Для простоты я исключил обработку исключений