Проверьте, содержит ли возврат доходности элементы

Я пытаюсь оптимизировать процедуру, которая выглядит примерно так (упрощенно):

public async Task<IEnumerable<Bar>> GetBars(ObjectId id){
    var output = new Collection<Bar>();

    var page = 1;
    var hasMore = true;

    while(hasMore) {
        var foos = await client.GetFoos(id, page);

        foreach(var foo : foos) {

            if(!Proceed(foo)) {
                hasMore = false;
                break;
            }

            output.Add(new Bar().Map(foo)
        }

        page++;

    return output;
}

Метод, который вызывает GetBars(), выглядит примерно так

public async Task<Baz> GetBaz(ObjectId id){
    var bars = await qux.GetBars();

    if(bars.Any() {
        var bazBaseData = qux.GetBazBaseData(id);
        var bazAdditionalData = qux.GetBazAdditionalData(id);

        return new Baz().Map(await bazBaseData, await bazAdditionalData, bars);
    }
}

GetBaz() возвращает от 0 до большого количества элементов. Поскольку мы проходим через несколько миллионов идентификаторов, мы изначально добавили оператор if(bars.Any()) в качестве начальной попытки ускорить приложение.

Поскольку ожидается GetBars(), поток блокируется до тех пор, пока он не соберет все свои данные (что может занять некоторое время). Моя идея состояла в том, чтобы использовать yield return, а затем заменить if(bars.Any()) проверкой, которая проверяет, получили ли мы хотя бы один элемент, чтобы мы могли тем временем запустить два других асинхронных метода (что также требует некоторого времени для выполнения).

Тогда мой вопрос, как это сделать. Я знаю, что System.Linq.Count() и System.Linq.Any() опровергают всю идею доходности, и если я проверю первый элемент в перечислимом, он будет удален из перечисляемого.

Есть ли другой/лучший вариант, кроме добавления, например, параметра out к GetBars()?

TL;DR: как проверить, содержит ли перечисляемое из yield return какие-либо объекты, не начиная его итерации?


person Asser    schedule 10.11.2014    source источник
comment
Поправьте меня, если у меня сложилось неправильное впечатление - вы пытаетесь найти способ узнать, содержит ли GetBars() какие-либо элементы, проверяющие первый элемент. Верно?   -  person Moti Azu    schedule 10.11.2014
comment
@мот это правильно. Я добавлю это к исходному вопросу.   -  person Asser    schedule 10.11.2014
comment
Является ли await client.GetFoos самой длинной частью вашего GetBars метода?   -  person Rawling    schedule 10.11.2014
comment
@Rawling Да, это так, однако я нашел способ реструктурировать некоторые вызовы API, чтобы я мог выполнить проверку нуля другим способом. Итак, вкратце: я не выполняю нулевую проверку возвращаемого значения GetBars().   -  person Asser    schedule 10.11.2014


Ответы (1)


На ваш фактический вопрос: «Как проверить, содержит ли перечисляемый результат возврата какие-либо объекты, не начиная его итерации?» ну, ты не знаешь.

Это так просто, вы не можете поставить точку, поскольку единственное, что вы можете сделать с IEnumerable, — это перечислить его. Однако вызов Any() не является проблемой, поскольку он «действительно» перечисляет только первый элемент (а не весь список), но невозможно ничего перечислить, поскольку многие ienumerables не существуют ни в какой форме, кроме формы конвейер (не может быть никакой резервной коллекции, невозможно проверить, есть ли у чего-то, что еще не существует, какие-либо элементы, по замыслу это не имеет смысла)

Изменить: также я не вижу выхода в вашем коде, вы смешиваете концепции ожидаемого и доходного (совершенно не связанные)?

person Ronan Thibaudau    schedule 10.11.2014
comment
Хорошо. Это довольно прямолинейно. Спасибо. Редактировать: так выглядит код до оптимизации. - person Asser; 10.11.2014