2017-06-22 9 views
0

私は一般的にフレームワークとスケーラをプレイするのが新しいです。テストし、同期と非同期の行動の違いを理解しようとしているときに、次のコードを使用して: 私の非同期コントローラがブロックされているのはなぜですか?

package controllers 

import play.api.mvc._ 
import play.api.libs.concurrent.Execution.Implicits._ 
import scala.concurrent.Future 

object Application extends Controller { 

    def async = Action.async { 
    Logger.info("async start") 
    val resultF = Future { 
     Thread.sleep(2000) 
     Logger.info("async end") 
     Ok 
    } 
    Logger.info("non-blocking") 
    resultF 
    } 

    def sync = Action { 
    Thread.sleep(2000) 
    Ok 
    } 

} 

は、アプリケーションを実行する場合、私は「/非同期」を要求するブラウザに10個のタブを持っています。私の期待は、すべての要求は、約2秒の間にfurfillを取る必要があり、私はログ10に "async start"エントリと、それに続く10個の "async end"エントリが表示されます。

しかし、実際の結果は「非同期開始」、「非同期終了」が10回ありました。次の要求は、前の要求が完了するまで開始しませんでした。非同期の実行がブロックされていて、同時要求を一切処理できないようです。

私の質問は、システムがこのように動作する理由と、同時要求処理を有効にするための具体的な変更内容です。

+0

https://www.playframework.com/documentation/2.5.x/ThreadPools ApacheBenchを示唆ため – danielnixon

答えて

0

コードは正常に動作します。

ab(ApacheBench)などを使用して同時リクエストを送信します。

> ab -c 5 -n 5 localhost:9000/async 
This is ApacheBench, Version 2.3 <$Revision: 1757674 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking localhost (be patient).....done 


Server Software:   
Server Hostname:  localhost 
Server Port:   9000 

Document Path:   /async 
Document Length:  0 bytes 

Concurrency Level:  5 
Time taken for tests: 2.013 seconds 
Complete requests:  5 
Failed requests:  0 
Total transferred:  375 bytes 
HTML transferred:  0 bytes 
Requests per second: 2.48 [#/sec] (mean) 
Time per request:  2013.217 [ms] (mean) 
Time per request:  402.643 [ms] (mean, across all concurrent requests) 
Transfer rate:   0.18 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  0 0 0.0  0  0 
Processing: 2008 2011 2.0 2011 2013 
Waiting:  2007 2011 2.0 2011 2013 
Total:  2008 2011 2.0 2011 2013 

Percentage of the requests served within a certain time (ms) 
    50% 2011 
    66% 2012 
    75% 2012 
    80% 2013 
    90% 2013 
    95% 2013 
    98% 2013 
    99% 2013 
100% 2013 (longest request) 

私は5つの同時要求を送信し、期待通りにすべて終了(Time taken for tests: 2.013 seconds上記参照)

+0

ありがとう:このようなものを使用します。 同じURLへの(GET)リクエストを作成するときに実際にブラウザと思われる問題は、クロムがキャッシュをロックして後続のリクエストをブロックする場合、この質問を参照してください: [同じリソースに複数のリクエストを送信するとChromeが停止しますか?](https://stackoverflow.com/questions/27513994/chrome-stalls-when-making-multiple-requests-to-same-resource) –

2

Action.asyncを使用すると、自動的にブロックしていないという意味ではありません。それはブロッキングAPIを使用しているかどうかによって異なります。

Thread.sleepはあなたのFutureにおけるブロッキング操作ですが、あなたは、あなたがそうしているExecutionContextへのシグナリングされていないので、動作は、使用すると、あなたのマシンが持っているどのように多くのプロセッサー何ExecutionContextによって異なります。あなたのコードは期待通りに動作しますExecutionContext.global

どちらの場合も、スレッドをブロックするThread.sleep(2000)を使用しています。

いずれの場合も、スリープコールはアクションのスレッドプールで発生します(これは最適ではありません)。

プレイスレッドプールを理解する上で述べたように:

プレイフレームワークは、ボトムアップ、非同期Webフレームワークから、です。ストリームは、iterateesを使用して非同期に処理されます。 play-coreのIOは決してブロックされないため、Playのスレッドプールは従来のWebフレームワークよりもスレッド数を減らすように調整されています。

このため、ブロックするIOコードやCPUを大量に使用する可能性のあるコードを作成する場合は、そのスレッドがどのスレッドプールに対応しているかを正確に把握する必要があります。 。あなたはちょうどあなたがすることができますスレッドをブロックしている場合は並列度のデフォルト設定は1

ある例をブロックするスレッド、両方に数秒間待っているあなたの場合

def async = Action.async { 
    Logger.info("async start") 
    val resultF = Future { 
     blocking{ 
     Thread.sleep(2000) 
     Logger.info("async end") 
     Ok 
     } 
    } 
    Logger.info("non-blocking") 
    resultF 
    } 
関連する問題