1

这是一个从缓冲源获取数据并将其发送以进行处理的片段。如果队列为空,则 get() 返回 null,并且 process 方法很乐意接受 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 行版本。

除了让编译器优化之外,这两种方法都只有一行,没有显式的中间变量,并且通过引用传递以避免复制,有什么通常可以让它运行得更快吗?我觉得我错过了一些明显的东西。

4

4 回答 4

3

我认为这是无用优化的最高案例

(你正在采取一些缓冲想要对其进行位优化的东西?)

此外,编译器将两种方式编译成完全相同的代码,并且(在大多数情况下)完全有权进行返回值优化尾调用优化。

结合 queue_class::get() 的可能内联,您的问题似乎完全没有意义

于 2011-04-28T08:50:27.613 回答
3

我相信您正试图在自己的工作中击败编译器。

您是否遇到过性能问题?如果没有,您可能会专注于生成可以维护的可读代码(您似乎拥有),而不是诉诸可能过早的优化并用奇怪的优化使代码混乱。

于 2011-04-28T08:52:43.607 回答
2

这段代码的问题不在于你做了什么,而在于它必须旋转——浪费你的计算机执行的其他一些任务可能已经使用的 CPU 周期——即使没有工作要做。

如果有许多程序采取这种态度(它们是计算机之王,并且会占用整个 CPU),那么一切都会慢下来。让你的代码像这样工作是一个非常激烈的决定。

如果可能,更改整个模型,以便在有更多可用数据时获得某种回调/信号/事件

于 2011-04-28T08:51:00.920 回答
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() 都使用大量代码,那么这样做可能意味着所有代码都可以保留在即时缓存中,而不是每次调用函数时都从另一个缓存中获取。

编译器无法进行这种优化,因为它可能不知道重新排序函数调用是安全的。

于 2011-04-28T08:50:50.940 回答