这是一个从缓冲源获取数据并将其发送以进行处理的片段。如果队列为空,则get()返回null,并且进程方法很乐意采用null并且不执行任何操作。 编写此代码的最佳方法是什么?
something a; // any legal C++ return type...
aQueueOfSomethings g;
while (true) {
a=g.get();
process(a);
}
没有办法预测通过get()到达的值,它们就是它们,并且它们需要被出列并尽快传递给process()。
我没有看到很多浪费的努力 - 如果我跳过名为'a'的显式局部变量并使循环成为一个班轮:
process(g.get());
g.get()的隐式返回值仍然会分配空间,可能涉及构造函数调用等,等等。
如果返回的东西有任何大小或复杂性,最好有一个指向它的指针而不是它的副本,并传递指针而不是按值复制...所以我宁愿有
something *a;
g.get(a);
process(a);
而不是
something a;
a=g.get();
process(a);
我用c ++编写了一个测试用例,尝试了两行和一行版本,循环100,000,000次。
如果a是一个有4个整数和2个浮点数的对象,并且process()方法全部触及它们,那么这两行解决方案实际上更快!如果a对象是单个int,则单行版本更快。如果对象很复杂但process()方法只触及一个值,则单行版本更快。
对我来说最有趣的是,使用g ++编译器,Mac OS X 10.5.8,-O第一级优化开关可以实现相同,更快的操作,同时具有1和2行版本。
除了让编译器优化,两个方法的单行和没有显式的中间变量,并通过引用传递以避免复制,是否有什么通常会使它运行得更快?我觉得我错过了一些明显的东西。
答案 0 :(得分:3)
我认为这是无用优化的最佳案例
(你正在采取缓冲和想要对其进行位优化的东西吗?)
此外,编译器将两种方式编译为完全相同的代码,并且(在大多数情况下)完全有权进行返回值优化和尾部调用优化。
结合可能内联的queue_class :: get()你的问题似乎完全是MOOT
答案 1 :(得分:3)
我相信你正试图在自己的工作中击败编译器。
您是否遇到过性能问题?如果没有,您可能会专注于生成一个可以维护的可读代码(您可以使用它),而不是诉诸于过早优化并使代码混乱的奇怪优化。
答案 2 :(得分:2)
此代码的问题不在于您所做的事情,而在于它必须旋转 - 浪费CPU 周期,而计算机正在执行的某些其他任务可能会使用 - 即使没有工作要做。
如果有很多程序采取这种态度(他们是计算机的王者,并且会占用整个CPU),那么一切都会慢慢变成绝对的爬行。让代码像这样工作是一个非常激烈的决定。
如果可能,请更改整个模型,以便在有更多可用数据时获得某种回调/信号/事件。
答案 3 :(得分:1)
你应该让编译器优化你是对的,但是如果你知道这样做是安全的:
while (true) {
a=g.get();
b=g.get();
c=g.get();
d=g.get();
process(a);
process(b);
process(c);
process(d);
}
那么它可能会让事情变得更快。
或者,甚至更极端,准备好返回类型(或指针)的整个数组,然后循环处理它们。如果process()和get()都使用了大量代码,那么这样做可能意味着所有代码都可以保留在立即缓存中,而不是每次调用函数时都从另一个缓存中获取。
编译器无法进行此优化,因为它可能不知道重新排序函数调用是安全的。
答案 4 :(得分:-1)
浪费精力 - 当你说:
时,你正在对operator =()进行不必要的调用a=g.get();
此外,某些东西可能不是默认构造的,在这种情况下你根本不能写第一个表格。