避免重复/循环展开

8

我有一个热点代码,它在一个紧密的循环中运行:

for (i = 0; i < big; i++)
{
    if (condition1) {
        do1();
    } else if (condition2) {
        do2();
    } else {
        do3();
    }
    // Shared code goes here
    // More shared code goes here
}

由于 condition1condition2 是不变的,我将循环展开到了

if (condition1) {
    for (i = 0; i < big; i++)
    {
        do1();
        // Shared code goes here
        // More shared code goes here
    }
} else if (condition 2) {
    for (i = 0; i < big; i++)
    {
        do2();
        // Shared code goes here
        // More shared code goes here
    }
} else {
    for (i = 0; i < big; i++)
    {
        do3();
        // Shared code goes here
        // More shared code goes here
    }
}

这种方法运行效果更好,但我想知道有没有聪明的方法可以避免重复呢?

也许你可以使用函数指针。根据条件设置它,然后在单个循环内使用它。 - Michael Albers
条件1和条件2在编译时已知吗? - Straw1239
1
@Straw1239:不,每次调用函数时它们可能会有所不同。 - Charles
2个回答

4

另一个可能稍微更有效的选项是使用宏来为您构建代码:

#define DO_N(name, ...) for(int i = 0; i < big; i++){name(__VA_ARGS__);/*shared code*/}

if (condition1) {
    DO_N(do1, .../*arguments here*/)
} else if (condition 2) {
    DO_N(do2, ...)
} else {
    DO_N(do3, ...)
}

#undef DO_N

这段代码可能不太美观,但我认为它能实现你想要的功能,并且可能比函数指针更容易内联。

此外,你可能会发现将共享代码放在单独的宏或函数中更易于阅读。


请查看我的另一条评论,其中通过函数指针的调用(可能)被内联。在得出性能结论之前,值得测量和尝试链接。 - chris
@chris 我看到了,知道编译器在这方面表现不错很好。我之前不确定,所以用了“可能”的说法。 - Straw1239
是的,我肯定会谨慎地假设它们会像这样轻松地内联。据我所知,函数指针更容易出现问题,而且在我的看法中,GCC需要一些刺激,以至于它可以完全消除该函数。 - chris

3

我认为你可以声明一个函数指针和一些名为foo()的函数:

typedef void (*fp)(void);

void foo(int big, fp f) {
    for (int i = 0; i < big; ++i) {
        f();
        // Shared code goes here
        // More shared code goes her
    }
}

然后将您的代码更改为以下内容:
if (condition1) {
    foo(big, do1);
} else if (condition2) {
    foo(big, do2);
} else {
    foo(big, do3);
}

是的,这是一个好主意。但是(抱歉!)我忘了提到,在我的代码中,do1、do2和do3具有不同的签名。 - Charles
2
@Charles,由于帖子中的do1(); do2(); do3();都使用相同的参数(无),因此这个答案很好地回答了这个帖子。也许您可以发布另一个帖子,加上您的限制条件。 - chux - Reinstate Monica
3
请注意,从性能角度来看,此解决方案的缺点是编译器无法将该函数内联。 - Ville Krumlinde
2
@VilleKrumlinde,通过一个人为制造的例子,GCC 内联 static 函数(或者 inline 函数),而 Clang 则将它们全部内联。这并不是说函数指针很容易内联,但是它们是可以内联的。 - chris
1
@chris 感谢您的示例,我学到了新东西!所以我的评论应该是“不太可能被内联”,而不是“不能”。 - Ville Krumlinde
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接