将 for 循环转换为多线程块

Convert a for loop to a Multi-threaded chunk

我在一个函数中有一个 for 循环,我打算将其并行化,但不确定多线程的负载是否会超过并发的好处。

我只需要将不同的日志文件发送到相应的接收者即可。暂时假设接收者的数量不会超过 10 个。与其来回发送日志文件,不如并行发送它们效率更高吗?

for(int i=0; i < receiversList.size(); i++)
        {
            String receiverURL = serverURL + receiversList.get(i);
            HttpPost method = new HttpPost(receiverURL);

            String logPath = logFilesPath + logFilesList.get(i);
            messagesList = readMsg(logPath);

            for (String message : messagesList) {
                StringEntity entity = new StringEntity(message);
                log.info("Sending message:");
                log.info(message + "\n");
                method.setEntity(entity);
                if (receiverURL.startsWith("https")) {
                    processAuthentication(method, username, password);
                }
                httpClient.execute(method).getEntity().getContent().close();
            }
            Thread.sleep(500); // Waiting time for the message to be sent
        }

另外请告诉我如果它可以工作,我怎样才能使它并行?我应该手动还是使用 ExecutorService?

Hello ExecutorService 当然是一个选项。 Java.

中有 4 种方法
  1. 使用线程(暴露了许多容易出错的细节)
  2. 您已经提到的执行者服务。它来自 Java 6 这是一个演示 ExecutorService 的教程 http://tutorials.jenkov.com/java-util-concurrent/executorservice.html
  3. ForkJoin框架来自Java7
  4. ParallelStreams 来自Java 8 以下是使用 ParallelStreams 的解决方案

追求更高的水平 api 会让您避免犯一些错误。

receiversList.paralelstream().map(t->{
                                      String receiverURL = serverURL + receiversList.get(i);
                                      HttpPost method = new HttpPost(receiverURL);

                                             String logPath = logFilesPath + logFilesList.get(i);
                                             return readMsg(logPath);
                                             })
                                     .flatMap(t->t.stream)
                                     .forEach(t->{
        StringEntity entity = new StringEntity(message);
                        log.info("Sending message:");
                        log.info(message + "\n");
                        method.setEntity(entity);
                        if (receiverURL.startsWith("https")) {
                            processAuthentication(method, username, password);
                        }
                        httpClient.execute(method).getEntity().getContent().close();})

All I need is to send different log files to corresponding receivers. For the time being lets say number of receivers won't be more than 10. Instead of sending log files back to back, is it more efficient if I send them all parallel?

在我们确定并行执行此操作是否会给您带来任何好处之前,有很多问题要问。你提到了 "receivers" 但你真的是在谈论不同网址上的不同接收服务器,还是所有线程都将它们的日志文件发送到同一台服务器?如果是后者,那么并发速度的提高可能会很小。单个线程应该能够很好地填充网络管道。

此外,如果消息很小,您可能无法加快速度。如果并行发送大型消息,它们会花费任何时间并真正节省开支。

我最熟悉的是ExecutorService类。你可以这样做:

ExecutorService threadPool = Executors.newFixedThreadPool(10);
...
threadPool.submit(new Runnable() {
    // you could create your own Runnable class if each one needs its own httpClient
    public void run() {
          StringEntity entity = new StringEntity(message);
          ...
          // we assume that the client is some sort of pooling client
          httpClient.execute(method).getEntity().getContent().close();
      }
    }
});

的好处是,如果您想将这些消息排队并在后台线程中发送它们,以免降低程序速度。然后您可以将消息提交到 threadPool 并继续前进。或者,您可以将它们放在 BlockingQueue<String> 中,并从 BlockingQueue 获取线程并调用 httpClient.execute(...).

来自此 good ExecutorService tutorial 的更多实施细节。

最后,将所有消息放在一个实体中并在服务器上划分消息如何。这将是最有效的,尽管您可能无法控制服务器处理程序代码。