改变具有“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];
}
}
}
重要:我知道这段代码无法编译。这是我必须优化的代码。
据我所知,有两种方法可以使该方法发挥作用:
convert
<前><代码>... 别的 { int索引 = this.GetSet(data); return this.keySets[index].Select(key => this.items[key]); }yield return
部分:转换
return
部分:if (this.isSingleSet) { foreach(this.singleSet 中的 TItem 项) { 收益回报项目; } } 别的 ...
但是两者之间有很大的速度差异。仅使用 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);
每个循环都在单独的进程中运行,因此垃圾收集或其他任何事情都不会影响性能。
- 我已经使用一种方法版本运行该程序,然后
- 关闭它
- 重写该方法并再次运行它。
这样做了几次才能看到可靠的性能差异......
I know it's impossible to use return
and yield return
in the same method.
This is the code that I would like to optimize:
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];
}
}
}
Important: I know this code doesn't compile. It's the code I have to optimize.
There are two ways that I know of that would make this method working:
convert
yield return
part:... else { int index = this.GetSet(data); return this.keySets[index].Select(key => this.items[key]); }
convert
return
part:if (this.isSingleSet) { foreach(TItem item in this.singleSet) { yield return item; } } else ...
But there's a big speed difference between the two. Using only return
statements (in other words using Select()
) is much much slower (like 6 times slower) to yield return
conversion.
Question
Is there any other way that comes to your mind how to write this method? Do you have any other suggestions information that would be valuable to performance discrepancy?
Additional info
I was measuring speed of the two methods by using stopwatch around a for
loop.
Stopwatch s = new Stopwatch();
s.Start();
for(int i = 0; i < 1000000; i++)
{
GetItems(GetRandomData()).ToList();
}
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds);
Each of these were loops were run in separate processes so there was could be no performance influence by garbage collection or anything else.
- I've run the program with one method version then
- Closed it
- Rewrote the method and run it again.
Did this few times to see reliable performance difference...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用两个函数。由客户端调用的外部函数执行您不想延迟的所有非惰性位(例如参数验证)。私人工作者做了一些懒惰的事情:
Use two functions. The outer, called by clients, function does all the non-lazy bits (like parameter validation) that you don't want to delay. The private worker does the lazy bits:
Select 的实现是(删除了错误检查):
所以我很难相信您使用的 Select 比您已经拥有的几乎相同的 foreach 循环慢得多。通过执行错误检查(一次)和创建委托(一次)以及通过委托间接进行的轻微开销,它会减慢速度。但循环机制应该是相同的。
然而,如果说我在性能分析中学到了一件事,那就是我的期望常常是完全错误的。您的分析运行表明您的应用程序存在哪些瓶颈?让我们根据事实来推理,而不是根据猜测。什么是热点?
The implementation of Select is (with the error checking removed):
So I have a hard time believing that your using Select is hugely slower than the almost-identical foreach loop you already have. It will be slowed down by doing error checking (once) and by creating the delegate (once), and the slight overhead of indirecting through the delegate. But the loop machinery should be identical.
However, if I've learned one thing in performance analysis, it's that my expectations are frequently dead wrong. What does your profiling run indicate is the bottleneck in your application? Let's reason from facts, not from guesses here. What is the hot spot?