概念的な利点と欠点
出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2021/04/05 03:33 UTC 版)
「ソフトウェアトランザクショナルメモリ」の記事における「概念的な利点と欠点」の解説
パフォーマンス的な利点に加えて、STM は概念的には非常に単純でマルチスレッドプログラムを理解しやすくするので、オブジェクトやモジュールのような高レベルな抽象化を進めることができ、プログラムをよりメンテナンスしやすくできる。ロックベースのプログラミングは実際にはしばしば非常に良く知られた問題にぶつかる。 処理的に離れているもしくはどうみても関連のなさそうな箇所のコードやタスク内の処理がかぶったりすることについて考える必要がある。これは非常に難しくてプログラマに対してエラーを誘発しやすい デッドロックやライブロック、その他処理を止めてしまうような問題を回避するために、プログラマはなんらかのロックを必要とする。このロック処理はしばしば無意識のうちに強制され誤りに陥りやすい。また、これらの問題が持ち上がった時には、それらを再現したりデバッグしたりするのが実は難しかったりする。 ロックは優先順位の逆転を引き起こす。これは優先度が高いスレッドが必要なリソースにアクセスしたいがために、優先度が低いスレッドに強制的に待たされるという現象である。 対照的にメモリトランザクションの考えは大変シンプルである。なぜなら、それぞれのトランザクションはあたかもシングルスレッドで動作しているかのように見えるからである。デッドロックやライブロックはまったく起きないか外部のトランザクションマネージャーによって制御されるので、プログラマはそのような問題について頭を悩ませる必要はまったくない。優先度逆転については課題として残るが、優先度が高いトランザクションはまだトランザクションが完了していない低い優先度のトランザクションとぶつかって処理が中断することはない。 他方、トランザクションの振る舞いにおいて、失敗したトランザクションを中止するのにも制限を設けたいこともある。たいていのI/O処理を含む、トランザクションがロールバックできない操作である。このような制限は普通実際にはバッファを作ることでやりくりする。このバッファによって、取り消せない操作をキューに入れたり、それらを他のトランザクションとは別にあとで実行したりする。 2005年に、Tim Harris、Simon Marlow、Simon Peyton Jones そして Maurice Herlihy によって STM が Concurrent Haskell 上に構築された。これは任意のアトミックな操作をより大きなアトミックな操作に合成することができる。この役に立つ考えはロックベースプログラミングでは不可能である。以下に筆者の言葉を引用する。 もしかしたら、最も根源的な意見は(中略)ロックベースプログラムは操作を合成できないことでないか。操作をくっ付けると元は正しい操作がうまくいかなくなってしまうかも知れない。例えば、スレッドセーフなハッシュテーブルに挿入と削除をすることを考えてみよう。ここで、アイテムAをテーブルt1から一つ削除し、それをテーブルt2に挿入することを考える。この時、中間の状態(すなわちアイテムAをどちらも含まない状態)は他のスレッドからは見ることができないとする。もしハッシュテーブルの実装者はこの要求を見越すことができなければ、この要求をちゃんと満たす方法はない。端的に言うと、個々に見れば正しい操作(挿入と削除)はより大きな正しい操作に作り直すことはできないのだ。 —Tim Harris et al., "Composable Memory Transactions", Section 2: Background, pg.2 STM においては、この問題は単純に解決できる。あるトランザクション中における2つの操作を単にラップしてアトミックな操作としてくっつけてしまえばよいのである。唯一の突っ込み所としてはこの処理を呼び出す側からははっきりしないことがある所である。つまり、コンポーネントが提供する方法の実装の詳細や、もし操作が失敗した場合に、そのトランザクションが再実行を試みるタイミングである。それに対して、筆者は retry コマンドを提案している。これは、トランザクションが失敗したときに生成されるトランザクションログを使って、どのメモリセルが読み出されたかを決定するものである。そして、これらのメモリセルのうちの一つが変更された時に自動的にトランザクションをリトライする。これは、少なくともある一つの値が変化するまでは、トランザクションの振る舞いは変わらないだろうという考えに拠っている。 筆者はまた、操作を合成するための代替手段を提案している。これは orElse というキーワードである。これは一つのトランザクションが走っていて、そのトランザクションが retry するならば、もう一方が実行されるというものである。もし両方リトライするならば、関連する変更がなされたらすぐに両方ともリトライしようとする。この機能は、POSIXのネットワークで使われる select() 呼び出しの特徴と比較される。orElse を使えば、呼び出し側は複数のイベントのうちどれか一つが変化するのを同時に待つことができる。この機能はまたプログラミングインタフェースを単純化できる。例えば、同期操作および非同期操作を相互に変換する機構を単純に作ることができる。
※この「概念的な利点と欠点」の解説は、「ソフトウェアトランザクショナルメモリ」の解説の一部です。
「概念的な利点と欠点」を含む「ソフトウェアトランザクショナルメモリ」の記事については、「ソフトウェアトランザクショナルメモリ」の概要を参照ください。
- 概念的な利点と欠点のページへのリンク