我有2个任务TaskA和TaskB,TaskA将被处理10次,taskB将被处理20次。现在有两个解决方案,如下所示 解决方案1:
for (int i = 0; i < 10; ++i)
{
// do taskA
}
for (int i = 0; i < 20; ++i)
{
// do taskB
}
解决方案2:
for (int i = 0; i < 20; ++i)
{
if (i < 10)
{
//do taskA
}
// do taskB
}
我想问一下解决方案1或解决方案2是否更适合性能和干净的代码?
答案 0 :(得分:4)
是否会产生任何性能差异是taskA和taskB的作用。但IMO,具有条件(i>10
)的单循环将使代码的可读性降低。
因此,您可以更清晰地制作等效代码:
for (int i = 0; i < 10; ++i)
{
// do taskA
// do taskB
}
for (int i = 10; i < 20; ++i)
{
// do taskB
}
这相当于解决方案2,并且更好地取决于任务A和B.
答案 1 :(得分:2)
正如已经多次指出的那样,这完全取决于“任务”是什么。
人们可能会争论“风格”或“可读性”,但这显然是主观的。
除了两点之外,没有太多的目标答案:
关于最佳实践,我想参考Separation Of Concerns。如果任务完全独立(并且它们显然是 - 否则你甚至没有机会改变执行顺序),那么关注点分离的原则建议将执行放入两个单独的循环中。所以这有利于您的第一个解决方案。人们甚至可以考虑更进一步,并将其分为两种方法:
void executeA(int times) {
for (int i = 0; i < times; ++i) {
// do taskA
}
}
void executeB(int times) {
for (int i = 0; i < times; ++i) {
// do taskB
}
}
并用这些方法替换循环:
executeA(10);
executeB(20);
(这里可能会更进一步,但可能会忽略问题的重点)
关于性能,通常没有太大差异,尽管细节可能取决于任务和编译器。现代编译器正在优化,可能甚至展开循环,因此第一个解决方案将等同于
taskA();
... // 10 times
taskA();
taskB();
... // 20 times
taskB();
,第二个解决方案相当于
taskB();
taskA();
... // 10 times
taskB();
taskA();
taskB();
taskB();
... // 10 times
taskB();
taskB();
即使未展开循环,Branch Prediction也会处理if
。但是,由于以下几个原因,第一解决方案仍然会更受欢迎:
后者指的是你可以简单地并行化一个简单的循环,如
for (int i = 0; i < times; ++i) {
taskA();
}
例如,在Java(或C ++中,假设您有适当的基础结构),您可以简单地将10个taskA
实例抛出到线程池中。同样用#pragma omp parallel
之类的东西注释这样的循环很容易(虽然我不熟悉OpenMP)。如果存在if
条件,则会干扰大多数并行化方法。
基于这些观察结果,我投票赞成解决方案1 。
答案 2 :(得分:1)
正如其他人所提到的,很大程度上取决于在这些循环中执行的任务类型。虽然默认选择应该是选项1以便于阅读。 有一种情况,其中选项1 应该选择的原因超过语法糖。如果任务A和任务B将在他们自己的内存块上工作locality of reference,那么最有可能胜过选项2。
例如:
for(int i = 0 ; i < 10; i++){
doSomething = dataBlockForTaskA[i]; // lots of cache hits
}
VS
for (int j = 0; j < 20; j++){
doSomething = dataBlockForTaskB[j]; // fetches some memory around BlockB
if ( j < 10 ){
doSOmething = dataBlockForTaskA[j] // oops cache miss
}
}
答案 3 :(得分:0)
根据您的示例解决方案2,基于您只循环一次的事实会更好。但是你必须考虑任务A与任务B中的逻辑。