简体   繁体   English

Java 中的随机 for 循环?

[英]Random for-loop in Java?

I have 25 batch jobs that are executed constantly, that is, when number 25 is finished, 1 is immediately started.我有25个不断执行的批处理作业,即当25个完成后,立即启动1个。

These batch jobs are started using an URL that contains the value 1 to 25. Basically, I use a for loop from 1 to 25 where I, in each round, call en URL with the current value of i , http://batchjobserver/1 , http://batchjobserver/2 and so on. These batch jobs are started using an URL that contains the value 1 to 25. Basically, I use a for loop from 1 to 25 where I, in each round, call en URL with the current value of i , http://batchjobserver/1http://batchjobserver/2等。

The problem is that some of these batch jobs are a bit unstable and sometimes crashes which causes the for-loop to restart at 1. As a consequence, batch job 1 is run every time the loop is initiated while 25 runs much less frequently.问题是其中一些批处理作业有点不稳定,有时会崩溃,这会导致 for 循环在 1 处重新启动。因此,批处理作业 1 在每次启动循环时都会运行,而 25 的运行频率要低得多。

I like my current solution because it is so simple (in pseudo code)我喜欢我当前的解决方案,因为它非常简单(在伪代码中)

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

However, I would like I to be a random number between 1 and 25 so that, in case something crashes, all the batch jobs, in the long run, are run approximately the same number of times.但是,我希望 I 是 1 到 25 之间的随机数,以便万一发生崩溃,从长远来看,所有批处理作业的运行次数大致相同。

Is there some nice hack/algorithm that allows me to achieve this?是否有一些不错的 hack/算法可以让我实现这一目标?

Other requirements:其他需求:

  • The number 25 changes frequently 25这个数字经常变化
  • This is not an absolut requirement but it would be nice one batch job wasn't run again until all other all other jobs have been attempted once.这不是一个绝对的要求,但最好在所有其他所有其他作业都尝试过一次之后再运行一个批处理作业。 This doesn't mean that they have to "wait" 25 loops before they can run again, instead - if job 8 is executed in the 25th loop (the last loop of the first "set" of loops), the 26th loop (the first loop in the second set of loops) can be 8 as well.这并不意味着它们必须“等待” 25 个循环才能再次运行,而是 - 如果作业 8 在第 25 个循环(第一个“组”循环的最后一个循环)中执行,则第 26 个循环(第第二组循环中的第一个循环)也可以是 8 个。

Randomness has another advantage: it is desirable if the execution of these jobs looks a bit manual.随机性还有另一个优点:如果这些作业的执行看起来有点手动,那是可取的。

To handle errors, you should use a try-catch statement.要处理错误,您应该使用 try-catch 语句。 It should look something like this:它应该看起来像这样:

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

This is a very basic example of what can be done.这是可以做什么的一个非常基本的例子。 This will, however, only skip the failed attempts, print the error, and continue to the next iteration of the loop.但是,这只会跳过失败的尝试,打印错误,然后继续循环的下一次迭代。

There are two parts of your requirement:您的要求有两个部分:

  1. Randomness : For this, you can use Random#nextInt .随机性:为此,您可以使用Random#nextInt
  2. Skip the problematic call and continue with the remaining ones : For this, you can use a try-catch block.跳过有问题的调用并继续其余的调用:为此,您可以使用try-catch块。

Code:代码:

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

Note: random.nextInt(25) returns an int value from 0 to 24 and thus, when 1 is added to it, the range becomes 1 to 25 .注意: random.nextInt(25)返回一个从024int值,因此,当向其中添加1时,范围变为125

You could use a set and start randomizing numbers in the range of your batches, while doing this you will be tracking which batch you already passed by adding them to the set, something like this:您可以使用一个集合并开始随机化批次范围内的数字,同时您将通过将它们添加到集合中来跟踪您已经通过的批次,如下所示:

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

As an extra, you can save which batches failed另外,您可以保存哪些批次失败

The following is an example of a single-threaded, infinite looping (also colled Round-robin ) scheduler with simple retry capabilities.以下是具有简单重试功能的单线程、无限循环(也称为循环)调度程序的示例。 I called "scrape" the routine that calls your batch job ( scraping means indexing a website contents):我将调用批处理作业的例程称为“抓取”(抓取意味着索引网站内容):

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");
    }
}

You may want to add multi-thread capabilities (that is achieved by simply adding an ExecutorService guarded by a Semaphore ) and some retry logic (for example only for certain type of errors and with a exponential backoff).您可能想要添加多线程功能(通过简单地添加由Semaphore保护的ExecutorService来实现)和一些重试逻辑(例如仅针对某些类型的错误和指数退避)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM