2016-07-26 2 views
0

私は、並列化しようとしているが、複数のスレッドの負荷が並行処理の利点を上回るかどうかわからない関数で、次のforループを使用します。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を使うべきですか?

答えて

1

は私が必要とするすべての対応するレシーバに異なるログファイルを送信することです。当分の間、受信者の数は10を超えないと言うことができます。ログファイルを連続して送信するのではなく、それらをすべて並列に送信すれば効率的ですか?

これを並行して実行すると何かを購入するかどうかを判断する前に、多くの質問があります。あなたは "レシーバ"について言及しましたが、実際には異なるWebアドレスの異なる受信サーバについて話しているのですか、またはすべてのスレッドが同じサーバにログファイルを送信していますか?後者の場合は、並行処理のスピードの向上はほとんどありません。単一のスレッドはネットワークパイプラインをうまく埋めることができるはずです。

また、メッセージが小さい場合はスピードアップしない可能性があります。大量のメッセージのみがいつでも受け取り、並行して送信された場合には本当の節約を行います。

私は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です。

最後に、すべてのメッセージを1つのエンティティに入れて、サーバー上のメッセージを分割する方法について説明します。これは、サーバーハンドラーのコードを制御しなくても、最も効率的です。

+0

ありがとうございます。私は別のマシンでログファイルとレシーバを持っているので、このシナリオでは、他のケースで言及したパフォーマンスを達成するでしょうか? – aneela

+0

複数の異なるマシンを使用している場合、異なるマシンにログファイルを起動すると、実際にパフォーマンスが向上する可能性があります。もっと細かいことなく本当に知るのは難しい@aneela。 – Gray

2

Hello ExecutorServiceは確かにオプションです。あなたはJavaでそれを行う4つの方法があります。

  1. 使用するスレッドは、すでに述べたよう
  2. キュータサービス(ミスをしやすい多くの詳細を公開します)。それはForkJoinフレームワークは、Java 7
  3. ParallelStreamsから来ExecutorServiceのhttp://tutorials.jenkov.com/java-util-concurrent/executorservice.html
  4. を実証チュートリアルでは、Java 8怒鳴るから来ている。ここでのJava 6 から来て、より高いレベルのAPIがあなたを惜しまますのために行くParallelStreams

を使用したソリューションでありますいくつかのエラーが発生する可能性があります。

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

ありがとうございますが、残念ながら私はJava 8を持っていません。負担がなければ、私は6または7の解決策を教えていただけますか? – aneela

関連する問題