Особенности работы Async/Await

198
06 марта 2018, 01:27

У меня есть следующая задача: необходимо в синхронной манере отправить запрос через шину данных и дождаться ответа, после чего вернуть управление вызывающему коду. А могу делать это асинхронно, давая возможность потоку выполнять другую работу. Количество слоев между вызывающим кодом(бизнес-логика) и диспетчером взаимодействия с шиной данных, к примеру, 5. Если я хочу использовать Async/Await, это значит, что на каждом уровне я должен пронести ключевые слова до первого void метода на самом верху. На каждом уровне теперь таск. Вопрос такой: Если в самом низу я реализую ожидание получения ответа через Task.Wait(а не комплишнСорс к примеру, то есть я буду ожидать ответа, блокируя поток), имеет ли какой-нибудь смысл весь этот синтаксический сахар наверху, ведь поток я все-равно заблокирую? Правильно ли я понимаю, что я сам должен побеспокоиться о том, чтобы мой код в самом низу(взаимодействие с шиной данных, жестким диском и пр..) был неблокирующим? В документации написано, что await не блокирует поток, при этом нет никакой доп. информации о том, что мне самому нужно делать соответствующую реализацию и беспокоиться об этом.

Answer 1

Использовать асинхронность имеет смысл в тех случаях, когда задача по своей природе - асинхронна. В таких случаях вам в любом случае придется обеспечивать синхронизацию с остальным кодом, и механизм задач тут - довольно простой вариант.

Если же на самом низком уровне все синхронно - то нет никакого смысла делать все асинхронным.

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

Рассмотрим ваш пример с шиной. Шина данных (если вы имеете в виду интеграционную шину) может работать несколькими способами. Самый простой из них - синхронные запросы по некоторому протоколу - вы просто делаете запрос и получаете ответ. Если это происходит по HTTP или TCP - то в стандартной библиотеке есть оба варианта API - синхронной и асинхронный. Нужно выбирать тот, который отвечает требованиям по быстродействию. Если у вас одновременно идут сотни или тысячи исходящих запросов - нужно использовать асинхронный вариант (и, конечно же, никаких блокировок на верхнем уровне!). Если вы делаете все запросы последовательно - то синхронного варианта вполне достаточно.

Но у вас упомянут какой-то диспетчер взаимодействия с шиной, значит все не так просто. Значит, шина возвращает ответы на запросы асинхронно и вперемешку, и вам необходимо их прослушивать в отдельном потоке. В таком случае у задачи очевидно асинхронная природа - и вам в любом случае нужна синхронизация. И TaskCompletionSource дает ее близким к оптимальному способом; странно его не использовать:

public Task<Response> SendRequestAsync (Request req)
{
    var tcs = new TaskCompletionSource<Response>(TaskCreationOptions.RunContinuationsAsynchronously);
    lock(requests) requests.Add(request.Id, tcs);
    // ...
    return tcs.Task;
}
public Response SendRequest (Request req) => SendRequestAsync(req).Result;
private void OnResponse(Response resp) 
{
    lock(requests)
    {
        TaskCompletionSource<Response> tcs;
        if (requests.TryGetValue(resp.RequestId, out tcs))
        {
            requests.Remove(resp.RequestId);
            tcs.SetResult(resp);
        }
    }
}

И нет никаких проблем с синхронным ожиданием через .Wait() или .Result если это необходимо (главное - следите в каком потоке вы это делаете).

READ ALSO
Узнать к какому типу относится символ

Узнать к какому типу относится символ

В общем, есть 2 строки, формат которых нужно проанализировать на похожесть

182
Работа с удаленным MySQL

Работа с удаленным MySQL

Собственно, купил хост для сайтаТам через cPanel создал новую SQL бд

164
Проверка на null перед GetValueOrDefault

Проверка на null перед GetValueOrDefault

Linq, метод Sum для nullable-типов:

160
Цветовая модель HSV(HSB). Перевод из RGB

Цветовая модель HSV(HSB). Перевод из RGB

Недавно сталкнулся с задачей, в одном элементе которой требовалось преобразование

150