[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends-ml 10923] Doug Lea 本



村山@netgeneです.

ここしばらくDoug Leaの「Javaスレッドプログラミング」を読んでた
のですが,本当にこれを理解した人っているんでしょうか?

この本は並列プログラミングの経験者にだって理解するのは困難です.
ましてやそうでない大多数の(ベテランプログラマーを含む)未経験者
が理解するのはほとんど不可能な気がします.

良くも悪くもエッフェル塔本みたいな本でした.

読書会でやった時も,十中八九,理解できなかったんじゃないかと思いますが,
どうでしょうかね.


○原書タイトル
"Concurrent Programming in Java: Design Principles and Patterns"

直訳すると
「Javaによる並列プログラミング:設計原理とパターン」
という感じで,この本自体は「マルチスレッド プログラミング」の
本じゃありません.私は見事に騙されました.
#あ,ちなみに,原書第二版(現時点の最新版)の訳本らしいです.
#てっきり初版だと思ってましたし,そういう風に間違って説明
#してたらごめんなさい.m(_ _)m
##「あの本は素晴らしい.是非読むべきだ」と勧めてたらこんな
##ものじゃ済まなかった気がする.

これをマルチスレッドプログラミングの本と思って買うと当てが
外れることになりますね.実際には並列プログラミングの本でさえ
ないようですが.

○非常に難解.
日本語訳がどうのというより,原文でも難解です.むしろ訳自体は,かなり
原文に忠実に,素直に訳しているようです.
#この本の難解さは原書を忠実に訳したことによる部分が多いと思う.
#Amazon.co.jpの書評は,あれは本当に原書を読んで書いたものだろうか?

この本は非常に回りくどい表現が多いし,新しく出てくる単語を定義しないまま
ズルズルと使っている部分も多い.それこそ"Concurrent Programming"さえも定
義してたかどうか.見出しなども内容を適切に表していないし,全体の章立ても
良くできているようには思えません.また同じことを意味するのに,場所によっ
て異なる単語を使ってると思しき箇所も多い.いずれも技術系の文書としては好
ましいものじゃありません.

また,あちこちで「これは違うだろ?」と言いたくなるような使い方をしている
単語も見られます.Reflectionのように専門用語を使っていながら専門的な意味
が無いので逆に混乱する部分もありました.

あちこちで「〜できる(can)」とか「〜かもしれない(may)」のような表現が使
われており,「〜となることが保証される」「〜するために,この部分を〜にす
る必要がある」というような明確な表現が少ない.

まるで「SOAP1.1仕様書」か「XML Schema仕様」を読んでいる気分になります.(^^;
#「〜できるとなってる箇所は,一体何が言いたいのか?そうしろと
#いうことなのか,純粋に可能性を議論しているのか,できるけど
#すべきではないと主張してしるのか....」と延々悩むことになる.


##どうも後で思ったのですが,この「気分」が実は真実かもしれません.
##同種なんですよ.Doug Lea本とSOAP1.1/XML Schemaは.
##これらは,おそらくXML業界用語でいう「貴族」だと思う.

○並列処理のハードウエアの解説が少ない,或いはない.
Cache Coherency Protocolの解説もなかった気がします.

volatileやsynchronizedが,実際にネイティブコードレベルでどの
ように実現されているのかという話も出てません.

この辺の話を理解していないと,本当の意味で効率の良いプログラムを書くのは
難しいと思います.まあ,実際にはC言語の頃ならば「同期を減らす」「疑似共
有を避ける」程度で,ほとんど困りませんでしたが.

これがJavaになると,HotSpotVMなどで行われている実行時の動的最適化の
話が絡んでくるので,話が数段複雑になります.その辺の話もあまり扱われて
いませんでした.
#結論についてはJavaでも似たようなもので,基本は「同期を減らす」
#だけでいいはず.あとはメモリモデルを守ること.
#「疑似共有を避ける」はJavaでは特に意識しなくても普通は避けられる
#ので,よほど変な設計でない限りは大丈夫なはず.

#逐次の「あたかもシリアル」の話はあったけど,パイプライン,スーパー
#スカラ,out-of-order実行などのハードウエアに関する説明もなかったが,
#こっちは基礎知識だから省略した可能性あり.


○パターンが未整理
パターンがズラズラと羅列されているものの,そのパターンがどんなもので,
他のパターンとどう違うのか,どのように関係するのか.その使い分けなどが
あまり明確ではない.

それに,ここで出ているのは「何度も利用されているベストプラクティス」
としてのパターンではなく,もっと小手先のイディオムレベルのような気が
します.しかも実用性の低い.

そもそも並列プログラミングにおいて「パターン」があるのかも疑問です.
#あるのはせいぜい「イディオム」や「設計戦略」程度で,
#再利用性のためのパターンと呼べるものが本当にあるかどうか.

○本当に並列プログラミングの本なのか?
並列プログラミングの根底にある基本法則(?)は,
「タイミングバグや同期のバグが出ると,デバッグに死ぬほど苦労する.」
というものです.
#前のJavaOneの"Performance Myths Exposed"でも,
#"Race-condition bugs are devilishly hard to find, fix and debug"
#という部分があります.
#並列のバグを経験した人なら「正にその通り!」と思うことでしょう.f(^^;

#その下に書かれている.
#"If you see heavy contention:
#   - Maybe need a different algorithm"
#というのも鉄則の一つです.

#普通に並列のプログラムを作成した時もそうですが,逐次プログラムを
#並列に「移植」した場合などは,逐次で効率の良いアルゴリズムが並列
#でも良いとは限らないので,特にこれが重要になります.

これらのバグには,デバッガもprint文さえも役に立つという保証は全く
ありません.だからこそ「少しでもデバッガが使えるように設計する」
というのが,いわばベストプラクティスになっていると思います.

この辺はJSPやServletにおける「テストしやすく作る」と同様ですね.Servlet
は極めてテストし難く,JSPはさらに輪をかけてテストしにくいので,可能な限
りこれらで行う処理を簡単にするのが鉄則です.制御ロジックの大半を普通の
Javaクラスで実現しておけば,JUnitによるテストが可能なのでそんなに手間は
かかりません.

同期なんかも同様で,同期のデバッグのし難さはJSP以上と言っても良いでしょ
う.だからこそできるだけ多くの部分を同期から切り離して「普通のJava」にカ
プセル化しておけばJUnitでテストできますし,デバッガも使おうと思えば使え
ます.テストのやりようのない「普通ではない/同期関係のJava」を最小限にし
ておけば,バグが出ても対応は比較的簡単です.

#実はJavaでのマルチスレッド/並列プログラミングがCの時代と一番違う
#のはここだったりします.前にも言ったかもしれませんが,C/C++だと
#「切り離したつもり」でも実際には切り離されていない.ポインタ周りに
#バグがあれば(普通はあるわけですが)カプセル化が簡単に破壊されるので,
#同期バグの影響はあらゆる箇所に及びます.これがJavaになると同期
#バグの影響は同期周りのみに限られます.
##Javaでしかやってないと,あの苦労はなかなか理解できないことでしょう.

この視点がDoug Lea本には欠けている気がしますし,少なくとも
説明が不十分です.


○理論中心で,複雑すぎて実践的でない.
たしかに様々なテクニックが紹介されてはいます.

ただ実際にはこれほど複雑な同期処理は,あまり実用的ではないと
思います.というのも,上で述べたように並列プログラミングの鉄則
としては
 「テストやデバッグが極めて困難だから,そもそもバグを出さないように作る.」
であり,そのためには
 「同期周りは極力シンプルに作る.」
他ありません.

これはプログラミングの効率の点からも,パフォーマンスの点からも
同じ結論が導けると思います.

そうすると,この本で紹介されているテクニックは,どうも不必要に話を
複雑にしています.C++的というかBertrand Meyer的というか,まあそんな
感じです.複雑にしすぎた結果,それを使うことが現実的でなくなってます.

○リファクタリングはリファクタリングではない.
同期処理のリファクタリングみたいな項目もありますが,おそらくあれは
リファクタリングではありません.

まず第一に,同期処理の変更はプログラムの挙動が変化を伴います.リファクタ
リングは挙動を変化させずに綺麗に書き直すことのはずです.しかし一般論とし
て同期の変更はアルゴリズムの変更を意味するし,大域的な影響を排除すること
もできません.それこそ,ほんの一行コードを書き加えただけで挙動が一変する
こともあります.これはリファクタリングの趣旨に反するものです.

第二に,同期処理はテストが構築できません.微妙なタイミングはそもそもテスト
不可能ですし,そうでなくともテスト自体が挙動を変更させる可能性を排除できま
せん.(ほとんど不確定性原理の世界.観測すること自体が状態に変更を加える
行為だから,元の状態を知る術はない.)十分なテストなしのリファクタリングは
無謀な試み意外の何物でもなく,既にリファクタリングとは言えない代物でしょう.

結局,同期部分だけはリファクタリングが不可能なので,最初に綺麗に設計し,
後からの変更は最小限に押さえるべき,ということになります.

○不変オブジェクト+ Copy on write.
既にご存じの方も多いですが,これが並列プログラミングで重要な
イディオムの一つです.安全なプログラムが結構素直に書けるので,
結構重宝します.

Doug Lea本にも,この話はあったかな?あったとしても,あまり重要な
扱いはされていませんでしたね.
#Effective Javaの方には少し書かれてたような気がする.

○Amazon.com
やっぱりAmazon.comの書評は一つ星から読むべきですね.非常に参考になります.
"His style is full of obfuscation and needlessly difficult to read. "

"I agree with other reviewers that this book is hard to read and understand. "

"I don't consider myself a beginner -- but I just could not read this 
book. It just jumps all over the place, using terms not in common 
practice, and not really building on anything."

今となってはこの辺りの意見に賛成です.
#必ずしも正確に理解できた自信はないですが.

この人達より私の方が有利だったのは,私はJava経験者というだけでなく並列プ
ログラミング経験者でもあったということ.なにせ並列プログラミング経験者な
んて無茶苦茶少ないですからね.たまたま大学でそれを専門にやったりしない限
りは,まず経験するチャンスがありません.おそらくこの書評を書いた人の中に
だって,そういう経験のある人はほとんどいないことでしょう.未経験者がこの
本を読んだだけで,並列プログラミングが理解できるとは到底思えません.

経験が無い限り「難解だ/理解できない」とは感じても,「間違っている」
ことや,「この本には並列プログラミングの重要な部分が,すっぽり抜け
落ちている」ことなどは分からない.