2017-03-20 17 views
0

私はJavaで非同期の利点を理解しようとしています。Java - 非同期 - スレッドプール

シナリオ1: 私は200

@Service 
public class MyService{ 

    public String execute(){ 
     try { 
      //simulate blocking 
      Thread.sleep(3000); 
     } catch (InterruptedException e) {} 
     return "OK";  
    } 
} 

@RestController 
public class MyController { 

    @Autowired 
    private MyService service; 

    @RequestMapping("/test") 
    public String test(){ 
     return service.execute(); 
    } 
} 

シナリオ2でのTomcat minとmaxのスレッドの両方を設定して、Tomcatにデプロイする春ブーツのWebアプリを、持っている:私は、Tomcatにデプロイする春ブーツのWebアプリを持っていますTomcatの最小値と最大値のスレッドそれぞれのシナリオで100

@Service 
public class MyService{ 

    public String execute(){ 
     try { 
      //simulate blocking 
      Thread.sleep(3000); 
     } catch (InterruptedException e) {} 
     return "OK";  
    } 
} 

@RestController 
public class MyController { 

    @Autowired 
    private MyService service; 

    private ExecutorService executorService = Executors.newFixedThreadPool(100); 

    @RequestMapping("/test") 
    public DeferredResult<String> test(){ 
     DeferredResult<String> deferredResult = new DeferredResult<>(); 
     CompletableFuture.supplyAsync(service::execute, executorService). 
      whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));  
     return deferredResult;  
    } 
} 

に両方のセットで、スレッドの合計数は200

あるしかし、私はどのようにSCEN表示されません

シナリオ1では、400リクエストが同時に入力された場合、最初の200は200のHTTPスレッドによって処理され、次の200は3秒待たなければなりません)スレッドの1つが再び利用可能になるまで。

したがって、スループットは400秒/ 6秒= 66.6要求/秒でした。

平均応答時間は、(200×3 + 200×6)/(400)= 4.5秒シナリオ2では

、 400個の要求が同時に入ってきた場合でした。最初の100は100個のHTTPスレッドによってすぐに処理され、これらのスレッドはそれぞれサービスを呼び出し、結果を待つことなくすぐに再開し、次の100個の要求を処理できるようになります。 しかし、2番目の100の要求では、各HTTPスレッドがサービスを呼び出すときに、そのサービスは現在3秒(マイナス1秒)待って最初の100スレッドの処理を終了します。次の100は(executorerviceのスレッドプール内の)キューに入れられます。 ほとんどの場合、ほとんどすべてのリクエストが処理されましたが、 100がサービスで処理されています(3秒間待機中)。300は実行者サービスのスレッドプールに入れられます。 3秒後に、最初の100件が完了し、次に100件がデキューされ、処理されます。

そこでスループットは12秒で400のリクエスト=第

平均応答時間であった (100×3 + 100×6 + 100 * 9 * 12 + 100)/(400)= 7.5当たり33.3要求であります秒

「実行可能サービスのスレッドプール内のスレッド数を増やしてシナリオ2を改善することができます」というメッセージが返ってきました。これは、「うん、その後、私は風袋内のスレッド数を増やす同じ量だけシナリオ1のプール '

答えて

0

このシナリオでは、非同期の利点を確認するには、あなたのサービスは非同期です。スレッドを結びつけるSleepを実行するのではなく、3秒後に完了するようにスケジューリングした後すぐに戻ります。この場合、すべての要求はわずか3秒で完了します。あなたのスループットは毎秒133要求となり、平均応答時間は3秒になります。また、スレッド数を調整した場合、本質的に同じ応答時間を持つことになります。

非同期のポイントは、I/Oを待っているアイドル状態のスレッドがすぐに何か他の処理を行うことができるため、作業負荷を満たすために高価なリソースであるスレッドを使用する必要がないことです。

+0

お返事ありがとうございます。 サービスが非同期であり、すぐに返された場合、完了可能な未来を完了するための応答を待っているスレッド –

+0

APIの呼び出し側は、依然として「OK」応答を待っています。いくつかのスレッドは、たとえTomcatのhttpスレッドでなくても、その応答を返す必要があります。 –

+0

@ jonathan.stiles - タイマータスクの時間が経過すると、タスクはスレッドプール上のアイドル状態のスレッドに割り当てられます。アイドル状態のスレッドがない場合、タスクはキューに割り当てられます。プールはアイドル状態になります。スレッドプールからのこのスレッドは、最終的にDeferredResultを完了し、その応答をクライアントに送信します。適切な非同期では、すべてのスレッドが作業を完了しているか、またはスケジュールされるのを待っているスレッドプール内でアイドル状態です。 – antlersoft

0

質問には非常に合成的な状況があります。

両方とも10のスレッド(非同期バージョンではHTTP 10個のスレッドと5個+ 5個のスレッド)があり、プログラムはスリープ状態のメソッドを呼び出す以上のものがあるとします。しかし、あなたの要求の80%は3秒を要します(データベースクエリを考えてみましょう)。

いずれの場合も、スレッドのすべてを同時にブロックする方法がありました。これまでのところ、大きな違いはありません。別の呼び出しがブロッキングメソッドに来たら、それは待たなければなりません。

今、突然、別の操作の要求があります。ログインとしましょう。ログインは簡単で、db内の行をチェックするだけです。最初のケースでは、サービスに利用できるHTTPスレッドがないため、3秒間待機する必要があります。 2番目のケースでは、完全に無関係のスレッドプールがありますが、ログイン用に使用していないので、すぐにログインリクエストが処理されます。

これで、DeferredResultを使用せずに1000スレッドプールを作成してみませんか?スレッドは高価です。高価なタスクを実行している1000スレッドを得て、CPUが100%で3秒ではなく実行時間が30秒になる状況に遭遇することは望ましくありません。サーバーのチョークとスループットは0になります。

これは接続プールにも当てはまります。少ないほうがいいですね。

+0

私はそれが公正な比較ではないと思います。'10の両方のスレッド ' それぞれに10のHTTPスレッドがあり、シナリオ2にも非同期サービスを処理するexecutorserviceがある場合、シナリオ2に実際にスレッドがあります。 –

+0

それは問題ではありません。 1つはすべての要求に対してX汎用スレッドを持ち、もう1つはY汎用スレッドを持ち、特定の長時間実行する操作(Y + Z = X)に対してはZスレッドを持ちます。 2番目の方法はスループットを向上させます。あなたの事例はとても悪い(現実には完全に根拠がない)、それはあなたを混乱させることです。この利点は*すべての*あなたの要求を非同期にするのではなく、待つのに多くの時間を費やす人のために自分で管理することから得られます。 – Kayaman

関連する問題