Ява должна использовать много циклов или один цикл и проверить условие внутри

У меня есть 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

Решение

Есть ли разница в производительности — вот что такое A и TaskB. Но ИМО, имея один цикл с условием (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.

4

Другие решения

Как уже указывалось несколько раз, все зависит от того, что представляют собой «задачи».

Можно спорить о «стиле» или «удобочитаемости», но это явно субъективно.

Так что не так много осталось для задача ответ, кроме двух пунктов:

  • Общие лучшие практики
  • Спектакль

Что касается лучших практик, я хотел бы сослаться на Разделение проблем. Если задачи полностью независимы (а они, очевидно, есть — иначе у вас не будет даже возможности изменить порядок выполнения), тогда принцип Разделение проблем предлагает поставить исполнение в два отдельных цикла. Так что это способствует вашему первый решение. Можно даже подумать о том, чтобы пойти еще дальше, и разделить их на два метода:

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();

Даже если петли не развернуты, Прогнозирование отрасли позаботится о if, Тем не менее первый Решение тогда будет по-прежнему предпочтительным по нескольким причинам:

Последнее относится к тому факту, что вы можете тривиально распараллелить простой цикл, как

for (int i = 0; i < times; ++i) {
taskA();
}

Например, в Java (или C ++, если у вас есть соответствующая инфраструктура), вы можете просто выбросить 10 экземпляров taskA в пул потоков. Также аннотирую такой цикл чем-то вроде #pragma omp parallel легко возможно (хотя я не знаком с OpenMP). Если есть ifпри условии, что это будет мешать большинству подходов распараллеливания.

На основании этих наблюдений я бы проголосовал за решение 1.

2

Как уже упоминалось, многое зависит от того, какой тип задачи выполняется в этих циклах. Хотя по умолчанию следует выбрать вариант 1 для удобства чтения.
Хотя есть один случай, когда вариант 1 должно быть выбор по причинам больше, чем синтаксический сахар. Если задача A и задача B будут работать на своих собственных блоках памяти местность ссылки будет, по всей вероятности, опередит вариант 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
}
}
1

В соответствии с вашим примером решение 2 будет лучше, если учесть, что цикл выполняется только один раз. Но вам придется учитывать то, что логика в задаче A против задачи B.

0