web-dev-qa-db-ja.com

Playの実行コンテキストvs scala global

実行コンテキストはどのように

import scala.concurrent.ExecutionContext.Implicits.global

playの実行コンテキストとは異なります。

import play.core.Execution.Implicits.{internalContext, defaultContext}
30
bjfletcher

彼らは非常に異なっています。

Play 2.3.x以前では、play.core.Execution.Implicits.internalContextは、サイズに一定の制約があるForkJoinPoolであり、Playによって内部的に使用されます。アプリケーションコードには決して使用しないでください。ドキュメントから:

Playの内部スレッドプール-これは、Playによって内部的に使用されます。このスレッドプール内のスレッドによってアプリケーションコードが実行されたり、このスレッドプール内でブロッキングが実行されたりしてはなりません。そのサイズは、application.confのinternal-threadpool-sizeを設定することで構成でき、デフォルトでは使用可能なプロセッサーの数になります。

代わりに、ActorSystemを使用するplay.api.libs.concurrent.Execution.Implicits.defaultContextを使用します。

2.4.xでは、どちらも同じActorSystemを使用します。これは、Akkaが独自のスレッドのプール間で作業を分散することを意味しますが、(構成以外の)ユーザーには見えません。複数のAkkaアクターが同じスレッドを共有できます。

scala.concurrent.ExecutionContext.Implicits.globalは、Scala標準ライブラリで定義されているExecutionContextです。これは、ForkJoinPoolメソッドを使用してブロックコードを処理し、プールに新しいスレッドを生成する特別なblockingです。 Playはそれを制御できないため、実際にはPlayアプリケーションでこれを使用しないでください。また、スレッドを大量に生成する可能性があります。注意しない場合は、大量のメモリを使用してください。

scala.concurrent.ExecutionContext.Implicits.globalについての詳細は this answer で記述しました。

44
Michael Zajac

それらは同じであり、Play、Akka、または組み合わせたアプリケーションの基になるアクターシステムのデフォルトディスパッチャーを指します。

デフォルトのPlayのコンテキスト

play.api.libs.concurrent.Execution.Implicits.defaultContext

Playの内部コンテキスト

play.core.Execution.Implicits.internalContext

注入されたGuiceのEC

class ClassA @Inject()(config: Configuration)
                           (implicit ec: ExecutionContext) {
...
}

しかし、これは異なるです。

scala.concurrent.ExecutionContext.Implicits.global

また、DBドライバー(例:スリックを使用する場合、独自の実行コンテキストが考えられる場合があります。とにかく、


ベストプラクティス:

  • scala.concurrent.ExecutionContext.Implicits.globalを使用しないでください。プレイ中またはakkaフレームワークでは、この方法で、高負荷時に最適よりも多くのスレッドを使用して、パフォーマンスが低下する可能性があります。
  • 恐れるな!ネットワーク接続をリッスンしたり、dbから明示的に読み取って結果を「現在の3つ」に待機させるなどのブロックタスクを実行しない限り、どこでも好きなだけデフォルトディスパッチャーを使用します。
  • デフォルトのエグゼキュータから開始し、高負荷時にPlay/Akkaがうまく応答しない場合は、時間のかかる計算タスクのために新しいスレッドプールに切り替えます。
    • 時間がかかる計算タスクは通常、ブロックとは見なされません。たとえば、メモリ内の自動補完ツリーをトラバースします。しかし、計算タスクを実行する時間があれば、制御構造を機能させたい場合は、それらをブロックしていると見なすことができます。
    • 計算タスクを非ブロッキングと見なすときに発生する可能性がある悪いことは、すべてのスレッドが高負荷で計算しているときに、再生およびAkkaメッセージディスパッチャーが一時停止することです。別のディスパッチャーの利点は、キュープロセッサが不足しないことです。別のディスパッチャーの短所は、最適なスレッドをより多く割り当てると、全体的なパフォーマンスが低下することです。
    • 違いは、高負荷のサーバーであり、小規模なプロジェクトでは心配しないで、デフォルトを使用します
  • アプリで他のエグゼキューターが実行されていない場合は、scala.concurrent.ExecutionContext.Implicits.globalを使用します。安全ですから心配しないでください。
  • Futureを作成したら、デフォルトのプールを使用します。futureがブロックしていることが確実でない限り、これが最も安全な方法です。次に、別のプールを使用するか、可能であればブロッキング{}構造を使用します。
  • 個別のスレッドプールを1回作成する
    • あなたAwait将来のために
    • あなたはThread.sleepを呼び出します
    • ストリーム/ソケット/ http呼び出しを読んでいます
    • ブロッキングドライバーを使用して手動でdbにクエリを実行します(通常はスリックが安全です)
    • タスクを10秒で実行するようにスケジュールする
    • タスクを毎秒実行するようにスケジュールする
  • 将来のマップ/リカバリー操作には、デフォルトのエグゼキューターを使用します。通常、これは安全です
  • 例外処理はデフォルトのディスパッチャーで安全です
  • 常にAkkaディスパッチャをPlayまたはAkkaは、application.confで新しいディスパッチャーを定義する素晴らしい方法があります
8