【问题标题】:c# combine yield return of multiple functionsc#组合多个函数的yield返回
【发布时间】:2019-07-10 04:56:12
【问题描述】:

c# yield compute 仅在调用者实际需要该特定枚举元素时才会延迟循环的每次迭代的执行。是否可以组合多个这样的收益返回函数,并且仍然向最终调用者公开一个动态枚举集?

public IEnumerable<string> GetDelayedCompute1()
{
    // compute ...
    foreach(var s in results)
    {
        yield return s;
    }
}

public IEnumerable<string> GetDelayedCompute2()
{
    // compute ... 
    foreach(var s in results)
    {
        yield return s;
    }
}

public IEnumerable<string> GetResults()
{
    // how to combine results of GetDelayedCompute1 and GetDelayedCompute2
    // and yield return without forcing enumeration
}

【问题讨论】:

  • 这与yield 无关——只要您的方法返回IEnumerable&lt;string&gt; 并且该方法中没有任何内容强制迭代,那么您会得到相同的结果。你可以做public IEnumerable&lt;string&gt; GetDelayedCompute1() =&gt; result.Select(s =&gt; s); 并得到懒惰的评估。

标签: c# return ienumerable concat yield


【解决方案1】:

LINQ 操作的结果是惰性求值的,因此您可以:

public IEnumerable<string> GetResults()
{
    return GetDelayedCompute1().Concat(GetDelayedCompute2());
}

在您枚举GetResults() 的结果之前,结果不会真正实现。

【讨论】:

    【解决方案2】:

    在 .Net4.8 中,Concat 比通过 foreach 的 yield return 慢得多。 我用 BenchmarkDotNet 对以下测试函数做了一个小基准测试:

    public IEnumerable<int> YieldReturn()
    {
        for (var i = 0; i < 100; i++)
        {
            foreach (var inner in this.Forward())
            {
                yield return inner;
            }
    
            foreach (var inner in this.Backward())
            {
                yield return inner;
            }
        }
    }
    
    private IEnumerable<int> Concat()
    {
        var result = Enumerable.Empty<int>();
    
        for (var i = 0; i < 100; i++)
        {
            result = result.Concat(Forward());
            result = result.Concat(Backward());
        }
    
        return result;
    }
    
    public IEnumerable<int> Forward()
    {
        for (var i = 0; i < 1000; i++)
        {
            yield return i;
        }
    }
    
    public IEnumerable<int> Backward()
    {
        for (var i = 1000; i > 0; i--)
        {
            yield return i;
        }
    }
    

    然后我让它运行 .Net4.8 和 .Net5.0。 结果如下:

    Method Job Runtime Mean Error StdDev Ratio RatioSD Gen 0 Gen 1 Gen 2 Allocated
    YieldReturn Job-IOETON .NET 5.0 2.668 ms 0.0720 ms 0.0428 ms 1.00 0.00 496.0938 496.0938 496.0938 2 MB
    YieldReturn Job-BBBSSF .NET Framework 4.8 2.854 ms 0.0997 ms 0.0659 ms 1.06 0.03 695.3125 667.9688 667.9688 3 MB
    Concat Job-IOETON .NET 5.0 1.922 ms 0.0388 ms 0.0257 ms 1.00 0.00 496.0938 496.0938 496.0938 2 MB
    Concat Job-BBBSSF .NET Framework 4.8 124.980 ms 4.6759 ms 3.0928 ms 65.03 1.81 600.0000 600.0000 600.0000 3 MB

    在“平均值”列中,您可以查看函数的持续时间。 所以在 .Net4.8 及以下我会使用收益返回解决方案。

    【讨论】:

      【解决方案3】:

      是否可以组合多个这样的收益返回函数

      是的,只需通过foreaching 对每个方法继续yield returns 的机制。

      foreach (var str in GetDelayedCompute1())
          yield return str;
      
      foreach (var str in GetDelayedCompute2())
          yield return str;
      

      否则Union结果并返回

       return GetDelayedCompute1().Union(GetDelayedCompute2());
      

      【讨论】:

        猜你喜欢
        • 2021-11-27
        • 2014-07-23
        • 2012-04-01
        • 2015-03-04
        • 1970-01-01
        • 1970-01-01
        • 2022-04-29
        • 2015-09-30
        • 2018-01-05
        相关资源
        最近更新 更多