scala学習十一同時プログラミング
9167 ワード
まず、生産者の消費者の例を示します.
Producer:
最後に、
しかし、プログラマは依然として2つのスレッド間の通信と協調の問題を過度に心配する必要があると述べた.一部のScalaメカニズムは文法を簡略化できるが,これまではそれほど魅力的ではなかった.
Scala同時性v 2
Scala Library Referenceには興味深いバッグがあります:
文字通り、
ここで、v 2とv 1との間の唯一の違いは、
したがって、この場合、2つのcaseクラスを作成します.1つはコンテンツを含まない(
明確なロックは不要であり、モニタを考慮する必要はありません.
Scala同時性v 3
実際には、
メソッド(ブロック上部の
オブジェクトインポート)あるコードブロック(別のby-nameパラメータの例)を受信し、匿名で構築されたスレッドオブジェクトの
メソッドの内部.実は、理解しにくいわけではありません.
の定義は
クラスの内部はどのようなものですか.
実際、Scalaの同時サポートは
および
クラス;Scalaはまた、同様の「Actors」概念をサポートし、
採用された方法は、類似のメッセージング方法であるが、より包括的で柔軟性が高い.
Producer:
class Producer(drop : Drop)
extends Runnable
{
val importantInfo : Array[String] = Array(
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
);
override def run() : Unit =
{
importantInfo.foreach((msg) => drop.put(msg))
drop.put("DONE")
}
}
Consumer: class Consumer(drop : Drop)
extends Runnable
{
override def run() : Unit =
{
var message = drop.take()
while (message != "DONE")
{
System.out.format("MESSAGE RECEIVED: %s%n", message)
message = drop.take()
}
}
}
Drop: class Drop
{
var message : String = ""
var empty : Boolean = true
var lock : AnyRef = new Object()
def put(x: String) : Unit =
lock.synchronized
{
// Wait until message has been retrieved
await (empty == true)
// Toggle status
empty = false
// Store message
message = x
// Notify consumer that status has changed
lock.notifyAll()
}
def take() : String =
lock.synchronized
{
// Wait until message is available.
await (empty == false)
// Toggle status
empty=true
// Notify producer that staus has changed
lock.notifyAll()
// Return the message
message
}
private def await(cond: => Boolean) =
while (!cond) { lock.wait() }
}
主Object:object ProdConSample
{
def main(args : Array[String]) : Unit =
{
// Create Drop
val drop = new Drop();
// Spawn Producer
new Thread(new Producer(drop)).start();
// Spawn Consumer
new Thread(new Consumer(drop)).start();
}
}
Producer
クラスとConsumer
クラスは、Javaクラスとほぼ同じであり、Runnable
インタフェースを再拡張(実装)し、run()
メソッドをカバーし、Producer
の場合には、importantInfo
配列のコンテンツを巡回するために内蔵反復メソッドをそれぞれ使用する.(実際には、Scalaのようにするために、importantInfo
はList
ではなくArray
であるべきかもしれませんが、最初の試みでは、元のJavaコードと一致することをできるだけ保証したいと思っています.)Drop
クラスは、Javaバージョンと同様です.しかし、Scalaにはいくつかの例外があり、「synchronized」はキーワードではなく、AnyRef
クラスに対して定義された方法、すなわちScala「すべての参照タイプのルート」です.これは、特定のオブジェクトを同期するには、そのオブジェクトに同期メソッドを呼び出すだけです.この例では、Drop
のlockフィールドに保存されているオブジェクトに対して同期メソッドを呼び出す.await()
メソッドで定義されたDrop
クラスでは、cond
パラメータは、メソッドに渡される前に計算を行うのではなく、計算を待つコードブロックであるというScalaメカニズムも利用していることに留意されたい.Scalaでは、これを「call-by-name」と呼ぶ.ここでは、Javaバージョンで2回表示する必要がある条件待ち論理(それぞれput
およびtake
)をキャプチャする実用的な方法である.最後に、
main()
でDrop
インスタンスを作成し、2つのスレッドをインスタンス化し、start()
を使用してそれらを起動し、main()
の終了部分で終了し、JVMはmain()
が終了する前に2つのスレッドを起動すると信じられる.(本番コードでは、このような状況は保証できないかもしれませんが、このような簡単な例では99.99%は問題ありません.)しかし、プログラマは依然として2つのスレッド間の通信と協調の問題を過度に心配する必要があると述べた.一部のScalaメカニズムは文法を簡略化できるが,これまではそれほど魅力的ではなかった.
Scala同時性v 2
Scala Library Referenceには興味深いバッグがあります:
scala.concurrency
.このパッケージには、MailBox
クラスを含む多くの異なる同時構造が含まれています.文字通り、
MailBox
は本質的にDrop
であり、検出前にデータブロックの単一スロットバッファを保存するために使用される.しかしながら、MailBox
の最大の利点は、単純なDrop
(またはDrop
のマルチスロットデータ保存クラスjava.util.concurrent.BoundedBuffer
)よりも柔軟に、送信および受信データの詳細をモードマッチングおよびcaseクラスに完全にカプセル化することである. package com.tedneward.scalaexamples.scala.V2
{
import concurrent.{MailBox, ops}
object ProdConSample
{
class Producer(drop : Drop)
extends Runnable
{
val importantInfo : Array[String] = Array(
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
);
override def run() : Unit =
{
importantInfo.foreach((msg) => drop.put(msg))
drop.put("DONE")
}
}
class Consumer(drop : Drop)
extends Runnable
{
override def run() : Unit =
{
var message = drop.take()
while (message != "DONE")
{
System.out.format("MESSAGE RECEIVED: %s%n", message)
message = drop.take()
}
}
}
class Drop
{
private val m = new MailBox()
private case class Empty()
private case class Full(x : String)
m send Empty() // initialization
def put(msg : String) : Unit =
{
m receive
{
case Empty() =>
m send Full(msg)
}
}
def take() : String =
{
m receive
{
case Full(msg) =>
m send Empty(); msg
}
}
}
def main(args : Array[String]) : Unit =
{
// Create Drop
val drop = new Drop()
// Spawn Producer
new Thread(new Producer(drop)).start();
// Spawn Consumer
new Thread(new Consumer(drop)).start();
}
}
}
ここで、v 2とv 1との間の唯一の違いは、
Drop
の実装であり、MailBox
クラスを使用して、Drop
から削除されたメッセージのブロックおよび信号トランザクションを処理する.(Producer
およびConsumer
を直接使用するように書き換えることができるが、単純性を考慮すると、すべての例におけるMailBox
APIを一致させることが望ましいと仮定する.)Drop
の使用は、典型的なMailBox
(BoundedBuffer
)の使用とは少し異なるので、コードをよく見てみましょう.Drop
には、MailBox
とsend
の2つの基本的な動作があります.receive
の方法は、タイムアウトに基づくreceiveWithin
にすぎない.receive
は、任意のタイプのメッセージを受信する.MailBox
メソッドは、メッセージをメールボックスに配置し、そのタイプのメッセージに関心のある待機受信者に直ちに通知し、後で取得するためにメッセージチェーンテーブルに添付する.send()
方法は、機能ブロックに適切なメッセージが受信されるまでブロックされる.したがって、この場合、2つのcaseクラスを作成します.1つはコンテンツを含まない(
receive()
)、これはEmpty
が空であることを示し、もう1つはメッセージデータを含む(MailBox
).Full
メソッドは、put
にデータを配置するため、Drop
に対してMailBox
を呼び出してreceive()
インスタンスを検索するため、Empty
が送信されるまでブロックされる.このとき、Empty
のインスタンスは、新しいデータを含むFull
に送信される. MailBox
メソッドは、take
からデータが削除されるので、Drop
に対してMailBox
インスタンスを呼び出してreceive()
インスタンスを検索し、メッセージを抽出し(caseクラスの内部から値を抽出し、ローカル変数にバインドする能力に再びモードマッチングのおかげで)、Full
インスタンスをEmpty
インスタンスに送信する. 明確なロックは不要であり、モニタを考慮する必要はありません.
Scala同時性v 3
実際には、
MailBox
とProducer
が機能的なクラスを必要としない限り、コードを著しく短縮することができます(ここではそうです).両者は本質的にConsumer
メソッドの痩せた包装器であり、ScalaはRunnable.run()
オブジェクトのscala.concurrent.ops
メソッドを使用して実装することができます. package com.tedneward.scalaexamples.scala.V3
{
import concurrent.MailBox
import concurrent.ops._
object ProdConSample
{
class Drop
{
private val m = new MailBox()
private case class Empty()
private case class Full(x : String)
m send Empty() // initialization
def put(msg : String) : Unit =
{
m receive
{
case Empty() =>
m send Full(msg)
}
}
def take() : String =
{
m receive
{
case Full(msg) =>
m send Empty(); msg
}
}
}
def main(args : Array[String]) : Unit =
{
// Create Drop
val drop = new Drop()
// Spawn Producer
spawn
{
val importantInfo : Array[String] = Array(
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
);
importantInfo.foreach((msg) => drop.put(msg))
drop.put("DONE")
}
// Spawn Consumer
spawn
{
var message = drop.take()
while (message != "DONE")
{
System.out.format("MESSAGE RECEIVED: %s%n", message)
message = drop.take()
}
}
}
}
}
spawn
メソッド(ブロック上部の
spawn
オブジェクトインポート)あるコードブロック(別のby-nameパラメータの例)を受信し、匿名で構築されたスレッドオブジェクトの
ops
メソッドの内部.実は、理解しにくいわけではありません.
run()
の定義は
spawn
クラスの内部はどのようなものですか.
<span style="background-color: rgb(153, 153, 153);"> def spawn(p: => Unit) = {
val t = new Thread() { override def run() = p }
t.start()
}</span>
実際、Scalaの同時サポートは
ops
および
MailBox
クラス;Scalaはまた、同様の「Actors」概念をサポートし、
ops
採用された方法は、類似のメッセージング方法であるが、より包括的で柔軟性が高い.