更改具有"返回"和"收益率"的方法

Rob*_*nik 6 c# return yield-return

我知道这是不可能的使用return,并yield return在同样的方法.

这是我想要优化的代码:

public IEnumerable<TItem> GetItems(int data)
{
    if (this.isSingleSet)
    {
        return this.singleSet; // is IEnumerable per-se
    }
    else
    {
        int index = this.GetSet(data);
        foreach(TKey key in this.keySets[index])
        {
            yield return this.items[key];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

重要提示:我知道此代码无法编译.这是我必须优化的代码.

我知道有两种方法可以使这种方法起作用:

  1. 转换yield return部分:

    ...
    else
    {
        int index = this.GetSet(data);
        return this.keySets[index].Select(key => this.items[key]);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 转换return部分:

    if (this.isSingleSet)
    {
        foreach(TItem item in this.singleSet)
        {
            yield return item;
        }
    }
    else ...
    
    Run Code Online (Sandbox Code Playgroud)

但两者之间存在很大的速度差异.仅使用return语句(换句话说使用Select())比yield return转换慢得多(比慢6倍).

有没有其他方法让你想到如何编写这个方法?您是否有任何其他建议信息对性能差异有价值?

附加信息

我通过在for循环周围使用秒表来测量两种方法的速度.

Stopwatch s = new Stopwatch();
s.Start();
for(int i = 0; i < 1000000; i++)
{
    GetItems(GetRandomData()).ToList();
}
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds);
Run Code Online (Sandbox Code Playgroud)

每个循环都在不同的进程中运行,因此垃圾收集或其他任何东西都可能没有性能影响.

  1. 我用一个方法版本运行程序然后
  2. 关闭它
  3. 重写该方法并再次运行它.

这几次看到可靠的性能差异......

Ric*_*ard 15

使用两个功能.由客户端调用的外部函数执行您不想延迟的所有非惰性位(如参数验证).私人工作者做懒惰的事情:

public IEnumerable<TItem> GetItems(int data) {
  if (this.isSingleSet) {
    return this.singleSet; // is IEnumerable per-se
  } else {
    return DoGetItems(data);
  }
}

private IEnumerable<TItem> DoGetItems(int data) {
  int index = this.GetSet(data);
  foreach(TKey key in this.keySets[index]) {
    yield return this.items[key];
  }
}
Run Code Online (Sandbox Code Playgroud)


Eri*_*ert 5

Select的实现是(删除了错误检查):

public static IEnumerable<R> Select<A, R>(
    this IEnumerable<A> sequence, 
    Func<A, R> projection)
{
    foreach(A item in sequence) 
        yield return projection(item);
}
Run Code Online (Sandbox Code Playgroud)

所以,我也很难相信您使用选择是巨大的比你已经拥有了几乎相同的foreach循环更慢.它将通过执行错误检查(一次)和创建委托(一次)以及通过委托间接的轻微开销来减慢速度.但循环机械应该是相同的.

但是,如果我在绩效分析中学到了一点,那就是我的期望经常是错误的.您的分析运行表明您的应用程序的瓶颈是什么?让我们从事实出发,而不是从这里猜测.什么是热点?