web-dev-qa-db-ja.com

マルチスレッド化が難しい理由を説明する方法

私はかなり優秀なプログラマーで、上司もかなり優秀なプログラマーです。彼はマルチスレッドなどのいくつかのタスクとそれがどれほど難しいかを過小評価しているようですが(私は、いくつかのスレッドを実行し、すべてが完了するのを待って結果を返す以外に何も非常に難しいことに気づきます)。

デッドロックと競合状態について心配しなければならない瞬間、私はそれが非常に難しいと感じますが、上司はこれを理解していないようです-彼がこれに遭遇したことはないと思います。それに鍵をかけるだけでかなりの態度です。

それでは、どうすれば彼を紹介できますか、または彼が並行性、並列処理、およびマルチスレッドの複雑さを過小評価している理由を説明できますか?それとも私は間違っていますか?

編集:彼がやったことについて少しだけ-リストをループし、そのリストの各アイテムについて、そのアイテムの情報に基づいてデータベース更新コマンドを実行するスレッドを作成します。彼が一度に実行するスレッドの数をどのように制御したかはわかりませんが、実行中のスレッドが多すぎる場合(セマフォを使用しなかった場合)、それらをキューに追加したはずです。

86
Mr Shoubs
  1. 数学的な経験を頼りにできる場合は、本質的に決定論的である通常の実行フローが、いくつかのスレッドで非決定論的であるだけでなく、exponentially complexになる方法を説明してください。まだ正しいことをします。失われた更新またはダーティリードの状況の簡単な例は、多くの場合目を見張るものです。

  2. 「それをロックする」is簡単な解決策...それはすべての問題を解決しますifパフォーマンスについて心配していません。たとえば、アトランタの誰かが1冊の本を注文したときに、Amazonが東海岸全体をロックしなければならなかった場合のパフォーマンスへの影響を説明してください。

29
Kilian Foth

マルチスレッドisシンプル。マルチスレッド用のアプリケーションのコーディングは非常に簡単です。

簡単なトリックがあり、これは適切に設計されたメッセージキューを使用して(do not自分でロール)、スレッド間でデータを受け渡します。

難しいのは、複数のスレッドが何らかの方法で共有オブジェクトを魔法のように更新することです。人々は存在する競合状態に注意を払わないので、それはそれが間違いを起こしやすいときです。

多くの人はメッセージキューを使用せず、共有オブジェクトを更新して問題を引き起こそうとします。

困難になるのは、複数のキュー間でデータを受け渡すときにうまく機能するアルゴリズムを設計することです。それは難しいです。しかし、(共有キューを介して)共存するスレッドのメカニズムは簡単です。

また、スレッドshare I/Oリソースにも注意してください。 I/Oにバインドされたプログラム(つまり、ネットワーク接続、ファイル操作、またはデータベース操作)は、多くのスレッドで高速に処理される可能性はほとんどありません。

共有オブジェクトの更新の問題を説明する場合、それは簡単です。紙のカードの束でテーブルを横切って座ってください。単純な計算セットを書き留めます。4〜6つの単純な数式を使用します。

これがゲームです。あなたはそれぞれ式を読み、答えを書き、答えのカードを置きます。

一人一人が半分の仕事をしますよね?半分の時間で完了しますよね?

上司があまり考えずに始めたばかりの場合、なんらかの形で矛盾が生じ、両方が同じ式に対する答えを書くことになります。書く前に読んでいる二人の間に固有の競合状態があるので、それはうまくいきませんでした。同じ数式を読んだり、お互いの答えを上書きしたりすることを妨げるものは何もありません。

リソースが不十分またはロックされていない状態で競合状態を作成する方法は数多くあります。

すべての競合を回避する場合は、用紙を数式のスタックにカットします。キューから1つ取り出し、回答を書き留め、回答を投稿します。どちらも1つのリーダーのみのメッセージキューから読み取るため、競合は発生しません。

79
S.Lott

マルチスレッドプログラミングは、おそらく同時実行性の最も難しいソリューションです。それは基本的に、マシンが実際に行うことのかなり低レベルの抽象化です。

アクターモデル(ソフトウェア)トランザクションメモリ など、より簡単なアプローチがいくつかあります。または、不変のデータ構造(リストやツリーなど)を操作します。

一般に、問題を適切に分離すると、マルチスレッド化が容易になります。忘れられがちなことですが、20個のスレッドを生成すると、すべて同じバッファーを処理しようとします。同期が必要なリアクタを使用し、通常、メッセージキューを持つ異なるワーカー間でデータを渡します。
アプリケーションロジックにロックがかかっている場合、何か問題がありました。

つまり、技術的には、マルチスレッド化は困難です。
「それに平手打ちをかける」は、並行性の問題に対するほとんどスケーラブルなソリューションではなく、実際にはマルチスレッドの目的全体を無効にします。問題は、問題を非並行実行モデルに戻すことです。実行すればするほど、実行中のスレッドが1つだけ(またはデッドロックでは0)になる可能性が高くなります。それは全体の目的を無効にします。
これは、「第3の世界の問題を解決するのは簡単です。爆弾を投げるだけ」と言っているようなものです。ささいな解決策があるからといって、結果の品質を気にするので、これは問題をささいなことにはしません。

しかし、実際には、これらの問題を解決することは、他のプログラミング問題と同じくらい難しく、適切な抽象化で行うのが最善です。実際、これは非常に簡単です。

25
back2dos

この質問には技術的でない角度があると思います。IMOは信頼の問題です。私たちは通常、たとえばFacebookなどの複雑なアプリを再現するように求められます。タスクの複雑さを初心者/管理者に説明する必要がある場合、デンマークでは何かが腐っているという結論に達しました。

他の忍者プログラマーが5分でタスクを実行できたとしても、見積もりは個人の能力に基づいています。あなたの対談者は、問題についてあなたの意見を信頼することを学ぶか、彼らが喜んで受け入れてくれる言葉を持つ誰かを雇うべきです。

課題は、人々が無視する傾向がある、または会話で把握できない技術的影響を中継することではなく、相互の尊重の関係を確立することです。

14
sunwukung

デッドロックを理解するための簡単な思考実験の1つに、「 食事の哲学者 」という問題があります。競合状態がいかに悪いかを説明するために私が使用する傾向がある例の1つは、 Therac 25 状況です。

「ロックをかけるだけ」とは、マルチスレッドで難しいバグに遭遇したことがない人の考え方です。そして、があなたが状況の深刻さを誇張していると考えている可能性があります(私はしません-ものを爆破したり、人々を殺すことは可能ですレースコンディションのバグ、特に組み込みソフトウェアが車に含まれる場合)。

6
Tangurena

2つの言葉で短い答え:OBSERVABLE NONDETERMINISM

長い答え:問題が与えられた場合、使用する並行プログラミングへのアプローチによって異なります。本 コンピュータプログラミングの概念、技法、およびモデル の中で、著者は並行プログラムを書くための4つの主な実用的なアプローチを明確に説明しています。

  • 順次プログラミング:同時実行性のないベースラインアプローチ。
  • 宣言的並行性:観察可能な非決定性がない場合に使用可能。
  • Message-passing concurrency:多数のエンティティ間での同時メッセージパッシング。各エンティティは内部的にメッセージを順次処理します。
  • 共有状態の同時実行性:スレッドを、粗いアトミックアクションを使用して共有パッシブオブジェクトを更新します。ロック、モニター、トランザクション。

このアプローチを使用して作成されたプログラムには観測可能な非決定性があるため、明らかな順次プログラミングとは別に、これら4つのアプローチの中で最も簡単なのは宣言的並行性です。言い換えると、競合状態は単なる観測可能な非決定的動作であるため、競合状態なしがあります。

しかし、観測可能な非決定性の欠如は、それが存在することを意味しますいくつかの問題があります宣言的な同時実行性を使用して取り組むことができません。ここで、最後の2つのそれほど簡単ではないアプローチが機能します。それほど簡単ではない部分は、観察可能な非決定性の結果です。現在は、どちらもステートフルコンカレントモデルに該当し、表現力も同等です。しかし、CPUあたりのコアの数が増え続けるため、メッセージパッシングライブラリの増加(たとえば、JVMの Akka )に見られるように、業界はメッセージパッシングの同時実行性に最近より関心を寄せているようです。またはプログラミング言語(例 Erlang )。

前述のAkkaライブラリは理論的なActorモデルに基づいており、ロック、モニター、トランザクションを処理する必要がないため、同時アプリケーションの構築が簡単になります。一方、ソリューションを設計するには別のアプローチが必要です。つまり、アクターを階層的に合成する方法を考える必要があります。まったく異なる考え方が必要であると言えるかもしれませんが、これは結局、プレーンな状態の共有同時実行を使用するよりもさらに難しい場合があります。

並行プログラミングis hardは観察可能な非決定性のためですが、特定の問題に適切なアプローチとそのアプローチをサポートする適切なライブラリを使用すると、多くの問題を回避できます。

3
Jernej Jerin

同時アプリケーションは確定的ではありません。プログラマーが脆弱であると認識した非常に少量の全体的なコードでは、スレッド/プロセスの一部が別のスレッドのどの部分に対して実行されるかを制御できません。テストは難しく、時間がかかり、同時実行に関連するすべての欠陥を見つけることはほとんどありません。発見された場合、しばしば微妙な欠陥は一貫して再現できないため、修正は困難です。

したがって、唯一の正しい同時アプリケーションは、おそらく正しいものであり、ソフトウェア開発ではあまり実行されないものです。その結果、メッセージの受け渡しが正しいことを証明するのは比較的簡単なので、S.Lotによる答えが最も一般的なアドバイスです。

3
mattnz

最初に、2つのスレッドを開始し、両方を同時に1〜100の範囲でコンソールに出力する単純なプログラムを見て、問題が発生する可能性があると教えられました。の代わりに:

1
1
2
2
3
3
...

あなたはこのようなものを得ます:

1
2
1
3
2
3
...

もう一度実行すると、まったく異なる結果が得られる場合があります。

私たちのほとんどは、コードが順次実行されると想定するように訓練されています。ほとんどのマルチスレッディングでは、これを当然のことながら取ることができません。

0