ゼミ: Learning Concurrent Programming in Scala
久野靖∗

2015.9.11• だから SBT をダウンロードしてぜひ動かしてみて□ Aleksandar Prokopec, Learning Concurrent Program-ming in Scala, Pack Publishing, 2014.

□ 各章末にはプログラミングの練習問題• 文字通り Scala で並行プログラミングの本• それぞれの章の概念を理解したか試せる→せひ 2〜3• さまざまなレベル (従来の低レベルから抽象化されたフレームワークまで) をひととおり扱う

1

個はやってみてほしい□ API メソッドの一覧を示したりは基本的にしない• API は ScalaDoc で見られるし、変更も頻繁にあるので本に向かない

Preface□ 並行性が広く使われるようになった ← マルチコア CPU □ 本書は並列 API の詳細まで学ぶのが目的ではない• かっては学術的な話題だったが今では実用的に必要• 重要な概念を把握することが目的• このため多くのライブラリやフレームワークが登場• 本書を読了したら各ライブラリの働きだけでなく「いかに考えるか」が分かる□ 言語/ライブラリ/フレームワークの抽象度 UP →いつ何を使うかの判断必要

1.2

What this book covers• 従来型のスレッド/ロック/モニタなどの知識だけでは不十分□ おおまかな話題単位で章に分割してある• 従来型のものの弱点を補う新たな並行フレームワー• 標準の並行 API に加え、複雑な機能や高レベルの抽クも知る必要
象化なども□ 本書では Scala を用いて高レベルの並行プログラミン• ch1 Introduction --- 並行プログラミングの必要、Scala 入門

グを扱う• ch2 Concurrency on JVM and Java Memory
Model --- 並行プログラミングの基本、スレッド• 並行に関するさまざまな話題を詳細まで扱う• 現代的な並行フレームワークについても扱うの生成消滅、共有メモリの操作□ 本書を通じて、理論的基盤の理解と実践的スキルの両方• ch3 Traditional Building Blocs ofConcurrency --- 伝 統 的 な 並 行 動 作 の 道 具 だを獲得て、スレッドプール、アトミック変数、並行コレク

1.1ション (あくまで基本的なところ)

How this book is organized• ch4 Asynchronous Programming with Futures
and Promises --- Scala
固 有 の 部 分 。

□ 実際に役立つため動く例題プログラムを扱う

future/promise API とその使い方□ 各プログラムは短く自己完結• ch5 Data-Parallel Collections --- 並 列 コ レ• しかし架空の例というわけではなく実際に必要な場クションを用いて操作を並列化することについて面の抽出• ch6 Concurrent Programming with Reactive
Extensions --- イベント駆動/非同期プログラミ□ 実際に自分で動かしてみることを薦める

ングで用いるフレームワーク• 各例題で新しい概念が学べるが、理解には実地に試すことが必要• ch7 Software Transactional Memory --ScalaSTM ライブラリを用いてより直観的に扱える共有メモリ操作を学ぶ∗ 筑波大学ビジネスサイエンス系

1• ch8 Actors --- これまでとは違うモデル。どのよ □ 本章では:うに並行性のための抽象を選ぶか/メッセージパッシ• 並行プログラミングの簡単な紹介
ングを使うやりかた• 並行プログラミングで Scala を使うと何がいいか• ch9 Concurrency in Practice --- こ こ ま で の• 本書に必要な範囲の Scala 入門
さまざまなライブラリをまとめ、どのように適切なものを選ぶかを扱う

3.1□ 順番に読むことを薦めるが、必要なところを拾って読むことも可Concurrent Programming□ 並行プログラミング:

プログラムは一群の並行計算の集まり

2

What you need for this book2.1

Installing the JDK• 並行計算どうしは重なって実行され実行の協調が必要• 並行プログラミングを正しくやるのは大変• 直列プログラミングのすべての落とし穴はそのまま□ (別にいいよね)

存続• それに加えて多数の新たな落とし穴

2.2• なんでそんなことするの?

Installing and using SBT□ 複数の利点□ やってみたけど、JAR を取って来て java コマンドで動□ 性能が向上する「かもしれない」

かすだけ• マルチコア CPU が普及したので、この理由から並行プログラミングに注文• scalaVersion は設定しない方がいいような…
• いちいち package はソースに書かなかったとのこと• 多くの例題ではプログラムを SBT と同じ JVM で動か □ I/O 操作が高速化する「かもしれない」
している (違う場合注記)• 直列プログラミングではポーリングとか色々しかけが必要

2.3

Using Eclips, IntelliJ IDEA, or another IDE• 並行プログラムならすぐに応答するようにできる• このためマルチコア以前から並行プログラミングがあった (そうなの?)□ 略)□ 実装や保守性の面で利点がある「かもしれない」

2.4

Who this book is for• 並行単位に分けて書く方が簡潔に書けるプログラムもある□ Scala を使ってはいるが一般的なことが学べる• UI、Web サーバ、ゲームエンジンなどはそういう例

2.5□ 本書では共有メモリを介してやりとりする並行プログラ

Conventions

ムを扱う□ (以下ずっと略)• これと対照的にメモリを共有しない複数のコンピュータの並行性も→分散プログラミング

31. Introduction• 分散プログラミングでは他のノードがいつこけるか分からないことが前提になるのでやっかい ←前提次

□ 「1CPU は限界で、これからはマルチ CPU だよ」(Gene第では?

Amdahl, 1967)• 本書でもところどころで分散プログラミングに触れ□ 並行プログラミングの歴史は長いが今日のマルチコアがる箇所がある

牽引力• 従来型の並行プログラミングだけでなく大きなパラダイムシフトも• すべての開発者にとって必須のスキルに2

3.2• やりたいのは「並列に計算して、値ができたら教えてね」

A brief overview of traditional concurrency• よりよいのは、値はあるものと思って先に進み、使□ コンピュータシステムにおける並行性 → HW レベル、OS

う時に使えること→ Future を使った非同期プログ

レベル、◎言語レベル

ラミング• 並行システムにおける複数の実行の調整→同期• さらにストリームを使うことで宣言的に並行性を扱うこともできる(synchronization)• 同期には同期メカニズムが含まれる□ 直列計算でも関数型スタイルは普及• 同期方式 → 複数の実行主体がどのようにやりとり• Python, Haskell, Ruby, Scala ではコレクション
に対する操作を関数で表現可能だし、フィルタなどするか• 共有メモリ型:

実行主体どうしはメモリを介し情報も使えるをやり取り• メッセージパッシング型:
メッセージでやり取り• これらでは実装ではなく目標を記述していると言える分散計算では実行主体は• 5 章ではデータ並列コレクションを示すが、これもこの一環□ 一番下のレベルでは実行主体ハプロセス/スレッド →□ 高レベル並行のもう 1 つのトレンドは特定タスクに特化

ch2したフレームワーク• プロセス間の同期はロックとモニタ• STM はメモリトランザクションに特化し、並列計算• 同期を通じて実行順を制御することであるスレッドの開始とかは扱わないがメモリに加えた変更が他のスレッドからはその後• メモリトランザクションはメモリの読み書きで「瞬時に起こる」と見なせるものを実現 → 7 章に見える□ スレッドやロックで並行プログラムを記述するのはしば• これにより低レベル並行のときに起きる問題を回避しば繁雑• このため通信チャネル、並行コレクション、バリア、計数ラッチ等いろいろなものが生み出された□ 高レベル並行フレームワークの中には分散をサポートするものも• データパラレル、メッセージパッシグがそう → 8 章• これらを用いると特定の並行パターンが容易に記述できる → ch3□ 伝統的な並行プログラミングは低レベルでさまざまな誤3.4りを産みがち• 例:

The advantage of Scala□ Scala は発展途上だが Java のように広く使われつつある

デッドロック、窮乏、データ競合、競合条件• 並行プログラミングのサポートが充実• Scala で並行プログラミングをする場合はこれらは• 多様なあらゆるスタイルの並行フレームワークがある

使わないのが普通• 並行プログラミングのための近代的で高レベルな API• しかしこれらの低レベルの知識を持っておくことは価値がある□ Scala の構文的な柔軟さのため、フレームワークを入れやすい

3.3

Modern concurrency paradigms• 1 級関数、名前パラメタ、型推論、パターンマッチなど→あたかも組み込み機能であるかのように API を□ より新しい並行パラダイムでは「どうやって」の代わり使えるに「何を達成」で記述する• これらの API は内部 DSL のように特定のプログラミングモデルを提供• 実際には低レベル/高レベルん違いはあまり明確でな
いし、異なるフレームワークどうしの間も連続して• 組み込みのように見せられる機能の例:

いる

アクター、STM、Future• ではあるが、新しいものは「宣言的」「関数型」の方向• しかし実際にはライブラリ。Scala は新言語を作る必要を無くす□ 2 章で扱うが、並行して値を計算するにはスレッドを作り開始させ、終了を待ち合わせて値を受け取る必要3

• 他の言語のように構文で苦労しない→多くのユーザにとって魅力□ 前記のをインスタンス生成して動かすには:object Test2 extends App {val printy = new Printer("Hi")printy.printMessage()printy.printNumber(5)}□ Scala は安全な言語 --- GC、配列の境界検査、ポインタ演算無し• 静的型検査→多くのエラーを実行前に検出□ Scala では単一のオブジェクトを生成できる• 並行プログラミングでは多くの問題が産まれるので安全なほど良い

object Test {val Pi = 3.14}□ Scala は JVM 上の言語→インタオペラビリティ• 既存の Java ライブラリが自由に参照可能□ Scala では trait を extends したクラスが作れる• Java からの移行が容易• trait はインタフェース、値、メソッド実装を含ん• スレッドモデル、メモリモデルも JVM で規定→並行動作もポータブルだもの• Java 互換フレームワークでも Scala が開発言語として使われる

3.5

trait Logging {def log(s: String): Unitdef warn(s: String) = log("WARN: " + s)
def error(s: String) = log("ERROR: " + s)}class printLogging extends Logging {def log(s: String) = println(s)}Preliminaries□ (プログラミングとか OOP とかは知っているものとしますよ…)

3.6□ クラスは型パラメタを持てる
class Pair[P, Q](val first: P, val second: Q)

Execution of a Scala program□ 1 級関数オブジェクト (lambda)□ 簡単なプログラムから

val twice: Int => Int = (x: Int) => x * 2

object SquareOf5 extends App {def square(x: Int): Int = x * xval s = square(5)println(s"Result: $s")}

□ 「=>」は引数と返値の間にないといけない。型は次のように省略可
val twice = (x: Int) => x * 2• これを実行するときのスタックとヒープのようすを□ 次のように宣言側を書いて定義側を省略も可
図 (p18) に示す• 以下、そのほかのさまざまな機能

3.7

val twice: Int => Int = x => x * 2□ 引数が lambda の本体内で 1 回しか現れないなら次のようにできる

A Scala primer□ 本書を読む上で必要な Scala の概観 (詳細な入門では

val twice: Int => Int = _ * 2ない)□ 1 級関数オブジェクトを使うことでコードのかたまりを値のように扱える。次の例では名前パラメタを使っている□ あいさつメッセージを出すクラス

class Printer(val greeting: String) {def printMessage(): Unit = println(greeting + "!")
def printNumber(x: Int): Unit = {println("Number: " + x)}}

def runTwice(body: =>Unit) = {bodybody}□ 名前パラメタは型の前に「=>」を付けることで指定できる。使う例• printMessage は引数 0 個、1 つの文のみを持つ• printNumber は引数 1 個 (型 Int)

runTwice {println("Hello")}• どちらも値を返さない (→ Unit)。Unit は省略してよい4□ for 式はコレクションの辿り/変換に便利

4Summary□ 並行プログラミングとは何か

for(i <- 0 until 10) println(i)□ Scala はなぜよいか□ 「0 until 10」は「0.until(10)」と同等 (オブジェク
トのメソッド呼び出しで「.」を省略できるところがある)□ for は常に foreach と同等

5(0 until 10).foreach(i => println(i))

Exercises□ 少しはやってみましょうね?

□ for-comprehension でデータの変換ができる
val negatives = for(i <- 0 until 10) yields -i□ これは次と同等
val negative = (0 until 10).map(i => -1*i)□ 複数の入力からマップすることもできる
val pairs =for(x <- 0 until 4; y <- 0 until 4) yield(x, y)□ これは次と同等
val pairs =(0 until 4).flatmap(x =>(0 until 4).map(y => (x, y)))□ このように for-comprehension では何重でもネスト可□ よく使うコレクションの例として Seq[T], Map[T],Set[T]
val mesg: Seq[String] = Seq("Hello","world", "!")

□ 文字列埋め込み聞こう「s"..."」
val magic = 7
val mynum = s"My Magic No. is $magic"□ パターンマッチも重要な機能□ 次の例ではマップから値を取り出し、有無をチェック
val sucs = Map(1->2, 2->3, 3->4)
sucs.get(5) match {case Some(n) => println(s"suc is: $n)case None=> println("not found")□ 大部分のオペレータはオーバーロード (再定義) 可能
class Position(val x:Int, val y:Int) {def +(that: Position) =new Position(x + that.x, y + that.y)}□ パッケージオブジェクトを定義してトップレベルのメソッドや値定義を格納できるpackage org
package object learningconcurrency {def log(msg: String): Unit =println(s"${Thread.currentThread.getNmae}: $msg")

5