Example17.9

「Example17.9」の編集履歴(バックアップ)一覧はこちら

Example17.9 - (2010/10/24 (日) 11:02:47) の最新版との変更点

追加された行は緑色になります。

削除された行は赤色になります。

#co(){ 17.9 Workers Here's an implementation of a compute server in Scala. The server implements a future method which evaluates a given expression in parallel with its caller. Unlike the implementation in Section 17.3 the server computes futures only with a predefined number of threads. A possible implementation of the server could run each thread on a separate processor, and could hence avoid the overhead inherent in context-switching several threads on a single processor. } ** 17.9 ワーカー Scala における&bold(){計算サーバー}の実装例を見てみましょう。サーバーは future メソッドを実装し、与えられた式をその呼び出し者と並列に評価します。 17.3節の実装とは異なり、サーバーはスレッドの事前定義された数字だけを持って future を計算します。サーバーの一つのあり得る実装では、別々のプロセッサ上で各スレッドを走らせることができ、シングルプロセッサ上で複数のスレッドを切り替える際のコンテキストスイッチングに伴うオーバーヘッドを回避できます。 import scala.concurrent._, scala.concurrent.ops._ class ComputeServer(n: Int) { private abstract class Job { type T def task: T def ret(x: T) } private val openJobs = new Channel[Job]() private def processor(i: Int) { while (true) { val job = openJobs.read job.ret(job.task) } } def future[A](p: => A): () => A = { val reply = new SyncVar[A]() openJobs.write{ new Job { type T = A def task = p def ret(x: A) = reply.set(x) } } () => reply.get } spawn(replicate(0, n) { processor }) } #co(){ Expressions to be computed (i.e. arguments to calls of future) are written to the openJobs channel. A job is an object with - An abstract type T which describes the result of the compute job. - A parameterless task method of type t which denotes the expression to be computed. - A ret method which consumes the result once it is computed. } 計算すべき式(つまり、future を呼び出すときの引数)は openJobs チャネルに書かれます。&bold(){ジョブ}(job) は次を備えた オブジェクトです。 - job の計算結果を表す抽象型 T - 計算すべき式を表す、引数のない、型 T の taskメソッド - いちど計算された結果をとる ret メソッド #co(){ The compute server creates n processor processes as part of its initialization. Every such process repeatedly consumes an open job, evaluates the job's task method and passes the result on to the job's ret method. The polymorphic future method creates a new job where the ret method is implemented by a guard named reply and inserts this job into the set of open jobs. It then waits until the corresponding reply guard is called. } 計算サーバーはその初期化中に n 個の processor プロセスを生成します。各プロセスは未処理の jobを繰り返し取り出し、job の task メソッドを評価して job の ret メソッドに結果を渡します。多相的な future メソッドは、reply という名前のガードを使って ret メソッドを実装している新しい job を生成し、その job を未処理 job の集合に入れます。そして、対応する reply ガードが呼ばれるまでウェイトします。 #co(){ The example demonstrates the use of abstract types. The abstract type t keeps track of the result type of a job, which can vary between different jobs. Without abstract types it would be impossible to implement the same class to the user in a statically type-safe way, without relying on dynamic type tests and type casts. Here is some code which uses the compute server to evaluate the expression 41 + 1. } この例は抽象型の使い方を示しています。抽象型 T は、job の結果型を記録し、異なる job に対しては異なる型をとることもできます。抽象型がなければ、ユーザは型キャストと動的な型テストへの信頼なしに、静的に型安全な方法で同じクラスを作ることはできないでしょう。次に、式 41 + 1 を評価する計算サーバーを使うコードを示します。 object Test with Executable { val server = new ComputeServer(1) val f = server.future(41 + 1) println(f()) } #center(){[[前ページ>Example17.8]] [[ 17 章>Chapter 17 Abstractions for Concurrency]] [[目次>ScalaByExample和訳]] [[次ページ>Example17.10]]} ---- #comment
#co(){ 17.9 Workers Here's an implementation of a compute server in Scala. The server implements a future method which evaluates a given expression in parallel with its caller. Unlike the implementation in Section 17.3 the server computes futures only with a predefined number of threads. A possible implementation of the server could run each thread on a separate processor, and could hence avoid the overhead inherent in context-switching several threads on a single processor. } #setmenu2(ex-r-menu) ** 17.9 ワーカー Scala における&bold(){計算サーバー}の実装例を見てみましょう。サーバーは future メソッドを実装し、与えられた式をその呼び出し者と並列に評価します。 17.3節の実装とは異なり、サーバーはスレッドの事前定義された数字だけを持って future を計算します。サーバーの一つのあり得る実装では、別々のプロセッサ上で各スレッドを走らせることができ、シングルプロセッサ上で複数のスレッドを切り替える際のコンテキストスイッチングに伴うオーバーヘッドを回避できます。 import scala.concurrent._, scala.concurrent.ops._ class ComputeServer(n: Int) { private abstract class Job { type T def task: T def ret(x: T) } private val openJobs = new Channel[Job]() private def processor(i: Int) { while (true) { val job = openJobs.read job.ret(job.task) } } def future[A](p: => A): () => A = { val reply = new SyncVar[A]() openJobs.write{ new Job { type T = A def task = p def ret(x: A) = reply.set(x) } } () => reply.get } spawn(replicate(0, n) { processor }) } #co(){ Expressions to be computed (i.e. arguments to calls of future) are written to the openJobs channel. A job is an object with - An abstract type T which describes the result of the compute job. - A parameterless task method of type t which denotes the expression to be computed. - A ret method which consumes the result once it is computed. } 計算すべき式(つまり、future を呼び出すときの引数)は openJobs チャネルに書かれます。&bold(){ジョブ}(job) は次を備えた オブジェクトです。 - job の計算結果を表す抽象型 T - 計算すべき式を表す、パラメータのない、型 T の taskメソッド - いちど計算された結果をとる ret メソッド #co(){ The compute server creates n processor processes as part of its initialization. Every such process repeatedly consumes an open job, evaluates the job's task method and passes the result on to the job's ret method. The polymorphic future method creates a new job where the ret method is implemented by a guard named reply and inserts this job into the set of open jobs. It then waits until the corresponding reply guard is called. } 計算サーバーはその初期化中に n 個の processor プロセスを生成します。各プロセスは未処理の jobを繰り返し取り出し、job の task メソッドを評価して job の ret メソッドに結果を渡します。多相的な future メソッドは、reply という名前のガードを使って ret メソッドを実装している新しい job を生成し、その job を未処理 job の集合に入れます。そして、対応する reply ガードが呼ばれるまでウェイトします。 #co(){ The example demonstrates the use of abstract types. The abstract type t keeps track of the result type of a job, which can vary between different jobs. Without abstract types it would be impossible to implement the same class to the user in a statically type-safe way, without relying on dynamic type tests and type casts. Here is some code which uses the compute server to evaluate the expression 41 + 1. } この例は抽象型の使い方を示しています。抽象型 T は、job の結果型を記録し、異なる job に対しては異なる型をとることもできます。抽象型がなければ、ユーザは型キャストと動的な型テストへの信頼なしに、静的に型安全な方法で同じクラスを作ることはできないでしょう。次に、式 41 + 1 を評価する計算サーバーを使うコードを示します。 object Test with Executable { val server = new ComputeServer(1) val f = server.future(41 + 1) println(f()) } #center(){[[前ページ>Example17.8]] [[ 17 章>Chapter 17 Abstractions for Concurrency]] [[目次>ScalaByExample和訳]] [[次ページ>Example17.10]]} ---- #comment

表示オプション

横に並べて表示:
変化行の前後のみ表示:
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。