【问题标题】:Check if yield return contains items检查收益返回是否包含项目
【发布时间】:2015-01-06 17:20:40
【问题描述】:

我正在尝试优化一个看起来像这样(简化)的例程:

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 到很多项目。由于我们运行了几百万个 id,我们最初添加了 if(bars.Any()) 语句作为加速应用程序的初步尝试。

由于等待GetBars(),它会阻塞线程,直到它收集到所有数据(这可能需要一些时间)。我的想法是使用yield return,然后将if(bars.Any())替换为检查我们是否获得至少一个元素,这样我们就可以同时启动其他两个异步方法(这也需要一些时间来执行)。

我的问题是如何做到这一点。我知道System.Linq.Count()System.Linq.Any() 违背了收益回报的整个想法,如果我检查可枚举中的第一项,它将从可枚举中删除。

除了向GetBars() 添加一个输出参数之外,还有其他/更好的选择吗?

TL;DR:如何检查来自 yield return 的枚举是否包含任何对象而不开始迭代它?

【问题讨论】:

  • 如果我有错误的印象,请纠正我 - 您正在尝试找到一种方法来了解 GetBars() 是否包含任何检查第一个元素的元素。对吗?
  • @mot 是正确的。我会将其添加到原始问题中。
  • await client.GetFoosGetBars 方法中最长的部分吗?
  • @Rawling 是的,但是我找到了一种方法来重组一些 api 调用,这样我就可以用另一种方式进行 nullcheck。简而言之:我不对GetBars()'返回值执行空检查。

标签: c# yield-return null-check


【解决方案1】:

对于您的实际问题“如何在不开始迭代的情况下检查来自收益返回的可枚举对象是否包含任何对象?”好吧,你没有。

就是这么简单,你不能用句号,因为你唯一能用 IEnumerable 做的就是枚举它。但是,调用 Any() 不是问题,因为“确实”仅枚举第一个元素(而不是整个列表),但不可能枚举任何内容,因为除了 a 之外,许多可枚举不以任何形式存在管道(可能没有支持集合,无法检查不存在的东西是否有任何元素,按设计这是没有意义的)

编辑:另外,我在您的代码中看不到任何收益,您是否混淆了可等待和收益概念(完全不相关)?

【讨论】:

  • 好的。这很简单,谢谢。编辑:这是优化前代码的样子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-11
  • 2012-08-26
  • 1970-01-01
  • 1970-01-01
  • 2011-07-01
相关资源
最近更新 更多