Случайный цикл for в Java?

#java #algorithm #for-loop #random

#java #алгоритм #цикл for #Случайный

Вопрос:

У меня есть 25 пакетных заданий, которые выполняются постоянно, то есть, когда число 25 завершено, немедленно запускается 1.

Эти пакетные задания запускаются с использованием URL-адреса, который содержит значение от 1 до 25. В принципе, я использую цикл for от 1 до 25, где я в каждом раунде вызываю URL-адрес en с текущим значением i , http://batchjobserver/1 , http://batchjobserver/2 и так далее.

Проблема в том, что некоторые из этих пакетных заданий немного нестабильны и иногда выходят из строя, что приводит к перезапуску цикла for на 1. Как следствие, пакетное задание 1 запускается каждый раз при запуске цикла, в то время как 25 выполняется намного реже.

Мне нравится мое текущее решение, потому что оно такое простое (в псевдокоде)

 for (i=1; i < 26; i  ) {
   getURL ("http://batchjob/"   Integer.toString(i));
}
 

Однако я хотел бы, чтобы I было случайным числом от 1 до 25, чтобы в случае сбоя все пакетные задания в конечном итоге выполнялись примерно одинаковое количество раз.

Есть ли какой-нибудь хороший хак / алгоритм, который позволяет мне достичь этого?

Другие требования:

  • Число 25 часто меняется
  • Это не является абсолютным требованием, но было бы неплохо, чтобы одно пакетное задание не запускалось снова, пока все остальные все остальные задания не будут выполнены один раз. Это не означает, что они должны «ждать» 25 циклов, прежде чем они смогут снова запуститься, вместо этого — если задание 8 выполняется в 25-м цикле (последнем цикле первого «набора» циклов), 26-й цикл (первый цикл во втором наборе циклов) может бытьтакже 8.

Случайность имеет еще одно преимущество: желательно, чтобы выполнение этих заданий выглядело немного вручную.

Комментарии:

1. for ... { try { getURL(...) } catch (Exception e) { /* handle e*/ } }

2. «выполнение этих заданий выглядит немного вручную»: что это значит?

3. Существует ли какая-либо зависимость между этими заданиями?

4. @Raffaele Нет (символы-заполнители)

Ответ №1:

Для обработки ошибок следует использовать оператор try-catch . Это должно выглядеть примерно так:

 for(int i = 1, i<26, i  ){
   try{
      getURL();
   }
   catch (Exception e){
      System.out.print(e);
   }
}
 

Это очень простой пример того, что можно сделать. Это, однако, только пропустит неудачные попытки, выведет ошибку и перейдет к следующей итерации цикла.

Ответ №2:

Есть две части вашего требования:

  1. Случайность: для этого вы можете использовать Random#nextInt .
  2. Пропустите проблемный вызов и продолжайте с оставшимися: для этого вы можете использовать try-catch блок.

Код:

 Random random = new Random();
for (i = 1; i < 26; i  ) {
    try {
        getURL ("http://batchjob/"   Integer.toString(random.nextInt(25)   1));
    } catch (Exception e) {
        System.out.println("Error: "   e.getMessage());
    }
}
 

Примечание: random.nextInt(25) возвращает int значение из 0 to 24 и, таким образом, при 1 добавлении к нему диапазон становится 1 to 25 .

Ответ №3:

Вы могли бы использовать set и начать рандомизацию чисел в диапазоне ваших пакетов, при этом вы будете отслеживать, какой пакет вы уже передали, добавив их в set, что-то вроде этого:

 int numberOfBatches = 26;
Set<Integer> set = new HashSet<>();
List<Integer> failedBatches = new ArrayList<>();
Random random = new Random();
while(set.size() <= numberOfBatches)
{
     int ran = random.nextInt(numberOfBatches)   1;
     if(set.contains(ran)) continue;
     set.add(ran);
     try
     {
         getURL ("http://batchjob/"   Integer.toString(ran));
     } catch (Exception e)
     {
         failedBatches.add(ran);
     }
}
 

В качестве дополнения вы можете сохранить, какие пакеты завершились неудачно

Ответ №4:

Ниже приведен пример однопоточного планировщика с бесконечным циклом (также с циклическим перебором) с простыми возможностями повтора. Я вызвал «scrape» процедуру, которая вызывает ваше пакетное задание (очистка означает индексацию содержимого веб-сайта):

 public static void main(String... args) throws Exception {
    Runnable[] jobs = new Runnable[]{
            () -> scrape("https://www.stackoverfow.com"),
            () -> scrape("https://www.github.com"),
            () -> scrape("https://www.facebook.com"),
            () -> scrape("https://www.twitter.com"),
            () -> scrape("https://www.wikipedia.org"),
    };

    for (int i = 0; true; i  ) {
        int remainingAttempts = 3;
        while (remainingAttempts > 0) {
            try {
                jobs[i % jobs.length].run();
                break;
            } catch (Throwable err) {
                err.printStackTrace();
                remainingAttempts--;
            }
        }
    }
}

private static void scrape(String website) {
    System.out.printf("Doing my job against %s%n", website);
    try {
        Thread.sleep(100); // Simulate network work
    } catch (InterruptedException e) {
        throw new RuntimeException("Requested interruption");
    }
    if (Math.random() > 0.5) {   // Simulate network failure
        throw new RuntimeException("Ooops! I'm a random error");
    }
}
 

Возможно, вы захотите добавить многопоточные возможности (это достигается простым добавлением ExecutorService защищенного a Semaphore ) и некоторой логики повторных попыток (например, только для определенного типа ошибок и с экспоненциальным возвратом).