Медленный код внутри async метода
От: meadow_meal  
Дата: 04.03.15 10:29
Оценка:
Здравствуйте,

Есть библиотека, предоставляющая апи для запросов к rest-сервису. В данный момент функции выглядят примерно вот так (упрощенно):
public Foo GetFoo(...)
{
    var request = WebRequest.Create(url) as HttpWebRequest;
    ...
    using (var resp = request.GetResponse())
    {
        using (var stream = resp.GetResponseStream())
        {
            using (var reader = new StreamReader(stream))
                return FooParser.Parse(reader);
        }
    }
}

то есть вызовы блокирующие, клиентский код использует треды. При отмене запроса тред "забывается".

В связи с обновлением проекта с .net 3.5 до 4.5 есть желание использовать async. Я вижу следующие варианты:

1) Библиотека не меняется, клиентский код использует Task.Run (если хочет).

2) Кроме GetFoo предоставлять GetFooAsync (и передавать CancellationToken). Соответственно вместо GetResponse использовать GetResponseAsync. Достоинство — мы экономим тред.

Но есть проблема: FooParser.Parse в общем случае может занимать значительное время — во-первых, из-за большого объема данных в ответе (т.е. вызовы к reader.Read будут блокировать), во-вторых, он для большого объема данных он будет медленный (до 1 с в редких случаях) сам по себе, если даже использовать reader.ReadToEndAsync.

Опять же, я вижу следующие варианты:

2а) Обернуть FooParser.Parse в Task.Run. Но непонятно, чем это лучше 1).

2б) Игнорировать проблему. Но тогда вызов GetFooAsync будет блокирующим, что совсем плохо.

2в) Реализовать FooParser.ParseAsync, внутри которого использовать асинк функции StreamReader. Предоставить клиентскому коду решать, использовать ли тред (Task.Run) или нет, так как клиентский код может сделать обоснованное предположение об объеме полученных данных. Достоинство этого варианта — можно правильно реализовать отмену (CancellationToken).

Какой вариант лучше? Как делают обычно?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.