2017-07-14 5 views
1

私は並列プロセスを実行するためにマルチスレッドを実現するために以下のようなプログラムを使用しましたが、完全に、私は5つのファイルをスレッドごとのデータと並行して書きますが、5つのうち4つのファイルが唯一の書き込みです。ExecutorServiceを使用する - 一部のプロセスで呼び出しメソッドが早期にタイムアウトしています

private static final Random PRNG = new Random(); 

    private static class Result { 
     private final int wait; 
     public Result(int code) { 
      this.wait = code; 
     } 
    } 

    public static Result compute(Object obj) throws InterruptedException { 
     int wait = PRNG.nextInt(3000); 
     Thread.sleep(wait); 
     return new Result(wait); 
    } 

    public static void main(String[] args) throws InterruptedException, ExecutionException 
      { 
     List<Object> objects = new ArrayList<Object>(); 
     for (int i = 0; i < 1000; i++) { 
      objects.add(new Object()); 
     } 

     List<Callable<Result>> tasks = new ArrayList<Callable<Result>>(); 
     for (final Object object : objects) { 
      Callable<Result> c = new Callable<Result>() { 
       @Override 
       public Result call() throws Exception { 
        return compute(object); 
       } 
      }; 
      tasks.add(c); 
     } 

     ExecutorService exec = Executors.newCachedThreadPool(); 
     // some other exectuors you could try to see the different behaviours 
     // ExecutorService exec = Executors.newFixedThreadPool(3); 
     // ExecutorService exec = Executors.newSingleThreadExecutor(); 
     try { 
      long start = System.currentTimeMillis(); 
      List<Future<Result>> results = exec.invokeAll(tasks); 
      int sum = 0; 
      for (Future<Result> fr : results) { 
       sum += fr.get().wait; 
       System.out.println(String.format("Task waited %d ms", 
        fr.get().wait)); 
      } 
      long elapsed = System.currentTimeMillis() - start; 
      System.out.println(String.format("Elapsed time: %d ms", elapsed)); 
      System.out.println(String.format("... but compute tasks waited for total of %d ms; speed-up of %.2fx", sum, sum/(elapsed * 1d))); 
     } finally { 
      exec.shutdown(); 
     } 
    } 

は、私たちは、プロセスがスレッドを完了すると達成するためにマルチスレッドのために何ができる任意のより良い解決策は、プロセスから終了する必要があります知っているかもしれないと私はJava8、

を使用しています、私は参照して同じコードを参照してください。

更新処理コード、

public String compute(String obj) throws InterruptedException { 
      MyProcess myProc=new MyProcess(writeFiles(obj)); 
      myProc.generateReport(); 
      } 
public void processMethod() {   
      List<Callable<String>> tasks = new ArrayList<Callable<String>>(); 
       for (final String object : list) { 
         Callable<String> c = new Callable<String>() { 
          @Override 
          public String call() throws Exception { 

           return compute(object); 
          } 
         }; 
         tasks.add(c); 
        } 

      ExecutorService exec = Executors.newCachedThreadPool(); 

        try { 
         long start = System.currentTimeMillis(); 
    List<Future<String>> results = exec.invokeAll(tasks); 
       String sum=null; 
       } 
       finally { 
          exec.shutdown(); 
         } 
         try { 
           exec.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 
          } catch (InterruptedException e) { 
      } 
    } 

がwriteFilesはすべて1回、この場合には、読み取りおよび書き込みデータをデータベースからローカルファイルにメモリに巨大であるとの違いが含まれている5つのファイルを比較する必要があります考えてみましょうファイルは書き込まれ、fo r他のものは1つのファイルしか書き込まれず、スレッドの合計時間がすべてのプールスレッドに共有されており、時間内にすべてのファイルを書き込むことはできません。

+0

@ holi-java正解。 'Thread.sleep'は指定された時間だけスリープ状態になることは保証されていませんが、少なくとも*その時間以上はスリープ状態になることが保証されていないため、さらに矛盾が生じました。 – Michael

+1

しかし、 'sleep()'も中断する可能性があります... –

+1

実際の問題が何であるかを理解するのは難しいです。私は、「スレッドが別のスレッドに移動している」、または「プロセスが完全に完了していない」ということはわかりません。特にいくつかの数値を実行して印刷するサンプルプログラムでは特にそうです。どのような数字が得られ、代わりにどの数字が期待されますか?これらの数字と「スレッドが別のスレッドに移動しています」または「プロセスを完全に完了していません」という関係は何ですか? – Holger

答えて

2

Future同時に又はで実行されているかどうかこれは順次ExecutorServiceに依存しています。あなたはExecutors.newCachedThreadPool()Executors.newSingleThreadExecutor()に変更した場合ので、その後の作業が順次ではなく、同時によりで実行され、その後、経過時間待ち時間の合計とほぼ同じです。例えば:

List<Callable<Result>> tasks = asList(() -> compute(null),() -> compute(null)); 


ExecutorService exec = Executors.newSingleThreadExecutor(); 

try { 
    long start = System.currentTimeMillis(); 
    List<Future<Result>> results = exec.invokeAll(tasks); 
    int sum = 0; 
    for (Future<Result> fr : results) { 
     sum += fr.get().wait; 
     System.out.println(String.format("Task waited %d ms", 
       fr.get().wait)); 
    } 
    long elapsed = System.currentTimeMillis() - start; 
    System.out.println(elapsed/sum); 
    //       ^--- 1 
} finally { 
    exec.shutdown(); 
} 

あなたはさらに、詳細でjava.util.concurrentパッケージの概要でそれを見ることができます:

Executorはスレッドを含むカスタム糸状サブシステムを、定義するためのシンプルな標準化されたインタフェースであり、プール、非同期I/O、および軽量のタスクフレームワークです。具体的な執行のクラスが使用されているによって、タスクは、新しく作成されたスレッドに既存タスク実行スレッドを実行することができる、またはスレッドがを実行呼び出し、そして同時に順次又はを実行することができます。

+0

説明してくれてありがとうございますが、私はスレッドプールを使用していますので、速度を向上させる必要があり、複数のスレッドを並行して実行する必要があります。3000と言うと、スレッドが完了すると終了する必要があります。スレッドが変化しています。 Executors.newSingleThreadExecutor()はシーケンシャルベースで実行されていますが、スレッドを終了する必要がある並列処理を完了する必要があります。同じことを達成するために何かができるかどうかを提案してください。 – user3428736

+0

@ user3428736あなたは私に例を挙げていただけますか?私は英語がうまくない。一度に3000のタスクを並行して実行したいですか? –

+0

私は3000のタスクを並列に実行する必要があります。個々のプロセスにはより多くの時間がかかるため、各スレッドはタスクを完了する前に終了します。 – user3428736

関連する問題