应该使用多个循环或一个循环并检查内部条件

Should use many the loop or one loop and check condition inside

我有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 哪个更适合性能和清洁代码?

根据您的示例,解决方案 2 会更好,因为您只循环一次。但是您必须考虑任务 A 与任务 B 中的逻辑。

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。 不过,在一种情况下,选项 1 应该 的选择不仅仅是出于语法糖的原因。如果任务 A 和任务 B 将在它们自己的内存块上工作,locality of reference 很可能会优于选项 2。

例如:

for(int i = 0 ; i < 10; i++){
     doSomething = dataBlockForTaskA[i]; // lots of cache hits
}

对比

for (int j = 0; j < 20; j++){
    doSomething = dataBlockForTaskB[j]; // fetches some memory around BlockB
    if ( j < 10 ){
         doSOmething = dataBlockForTaskA[j] // oops cache miss
    }
} 

正如已经多次指出的,这完全取决于 "tasks" 是什么。

有人可能会争论 "style" 或 "readability",但这显然是主观的。

因此 objective 答案所剩无几,除了两点:

  • 常见的最佳做法
  • 性能

关于最佳实践,我想参考Separation Of Concerns。如果任务是完全独立的(而且它们显然是 - 否则你甚至没有机会更改执行顺序),那么 Separation of Concerns 的原则建议将执行放入两个独立的循环。所以这有利于您的 first 解决方案。甚至可以考虑更进一步,将它们分为两种方法:

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++,假设您有适当的基础架构)中,您可以简单地将 taskA 的 10 个实例放入线程池中。也很容易用 #pragma omp parallel 之类的东西注释这样的循环(尽管我不熟悉 OpenMP)。如果存在 if 条件,这将干扰大多数并行化方法。

因此,根据这些观察结果,我会投票支持解决方案 1