Haskell による並列・並行プログラミング #10 担当: wado さん
p.136 7.5 組み立て部品としてのMVar:無制限チャネル 続き
unGetChan
先頭に値を戻す操作(cons)
チャネルが空になっていたときに困る
デッドロック
p.141 7.6 公平性
理想としてはどのスレッドにも等しくCPU時間が割り当てられてほしい
無理
GHCのスケジューラは、「CPU時間の割当を受けられないスレッドがないことを保証する」
putMVarを実行した時にブロックが解除されるのは1つのスレッドだけ
ソフトウェアトランザクショナルメモリでMVarが完全には置き換わらない理由になっている
担当: lotz さん
p.143 8章 入出力の重ね合わせ
MVarを使ったプログラミングでは簡単な処理もちょっと冗長になる
AsyncというMVarのラッパーをつくる
async :: IO a -> IO (Async a)
wait :: Async a -> IO a
takeMVar ではなく readMVar を使う
8.1 Haskellの例外
throw :: Exception e => e -> a
ErrorCall を使って例外を投げる
現在はコールスタックを出力するための機構が実装されている
catch :: Exception e => IO a -> (e -> IO a) -> IO a
独自の例外をつくる
Typeable をderivingすると例外をつくれる
catchを使うときはどのエラー型とマッチさせるか明示的に書く必要がある
try :: Exception e => IO a -> IO (Either e a)
例外の型の注釈が必要
handle = flip catch
onException :: IO a -> IO b -> IO b
onException (例外を投げ売る処理) (ハンドリング処理)
throwIO :: Exception e => e -> IO a
実行順序を厳密に保証してくれる(throwはそうではない)
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (リソース確保) (リソースを開放する処理) (リソースが得られた場合の処理)
finally :: IO a -> IO b -> IO a
リソース確保、リソース開放のみに限定
教科書の定義はちょっとおかしい
8.2 Asyncのエラー処理
example4
Asyncの中で発生した例外がforkIOしたスレッドで捕捉されるが、誰もMVarにputしなくなってしまったのでwait側が永遠に待つことになってしまう
修正しましょう
newtype Async a = Async (MVar (Either SomeException a))
forkIO (try action >>= putMVar var) とするので、例外が起きたらMVarに例外値が書き込まれる
wait側では例外が帰ってくることを想定したコードにする
例外が帰ってきたらthrowIOする(例外の伝搬)
複数実行したら、どれか1つでも失敗すると、全体として失敗する
8.3 マージ
逆に、どれか1つでも成功したら次に進む、というのをやりたい
全部おなじMVarにつっこむ→takeMVar すると、最速のものが手に入る
asyncの機能だけを使って提供したい
waitEither :: Async a -> Async b -> Async (Either a b)
LeftとWriteのうち早い方が書き込まれる
一般化(リストなので型は全部同じになるけど)
waitAny :: [Async a] -> IO a
どれか1つでも非同期処理が終わればそれを取り出して返す
p.157 9章 キャンセルとタイムアウト
担当: maton