質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

2262閲覧

Dictionary型のオブジェクトのKEY VALUEペアのロック

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2017/01/25 03:53

編集2017/01/25 04:02

お世話になっております。

C#で既存プログラムの実装の高速化をしたいと思っています。
以下のような木構造があり、それぞれのノードにはDictionaryでenum型に応じたkeyとdouble型のスコア値をvalueとして格納しています。
それぞれのエッジのスコアをrootから順に合計し、それぞれの枝について一番深いノードのスコア(図の赤色のスコア)を合計して出したいと思っています。

イメージ説明

実際はもっと複雑なアルゴリズムでノード間のスコアを決めるためにノードごとに共有される変数が必要になり、単純にそれぞれのスコアタイプごとにツリー構造をインスタンス化して並列化するという解決策は難しいということを前提としてください。

エッジのスコアとrootのスコアの初期値は既知でノードごとのスコアの累積和が未知の時に木構造の最も深いノードのスコアの累積和を求めるプログラムを書くと以下のようになりました。

一度通ったノードであれば再計算する必要がないのでそれぞれのノードにそのノード時点でのスコアの累積和を(Ditcionary<int,double> score)にキャッシュさせ、一度計算した経路については親の累積スコアを使いまわすことで計算を効率化するようにしています。

C#

1class Program{ 2 static double ROOT_SCORE=0.1; 3} 4class Node{ 5 6 7 public Ditcionary<int,double> score; 8 private Dictionary<int,double> _edgeScore; 9 //constructor 省略 10 double edgeScore(int stype){ 11 return _edgeScore[stype]; 12 } 13 public double calcScore(int stype,bool recalc=false) 14 { 15 if (score.ContainsKey(type)&&!recalc) { 16 return score[stype]; 17 } 18 if (parent != null) 19 { 20 score[stype] = edgeScore(stype) 21 score[stype] += parent.calcScore(score,recalc); 22 return score[stype]; 23 } 24 else 25 { 26 return ROOT_SCORE; 27 } 28 } 29 30} 31 32//末端のNodeは取得できる 33//List<Node> deepestNodes = new List<Node>{deepNode1,deepNode2}; 34//deepestNodes.Select(node=>types.Select(type=>node.calcScore(type)));

このとき、この処理をtypeごと,末端nodeごとに並列化したいのですがこれらの並列化にはDictionary scoreの排他制御。をしなければいけないと思うのですが。Dictionaryごとロックする方法は出てくるのですが、Dictionaryインスタンスすべてをロックするのは効率が悪いのでDictionaryのkeyの参照先のオブジェクトの書き込みの排他制御を行いたいと思っています。(つまり、要約するとstypeごとの実行はほかのstypeと競合しないので並列化,stypeの中ではノードの分岐点までは並列化,分岐点では排他制御がしたいということです。)このようなことは可能なのでしょうか?よろしくお願いいたします。

必要があれば、子から親までのパスはノードを作るときに作成できます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ノードをロックしたいのであれば lock(node) でできますので、それを葉に向かって再帰的に適用すればいいのかなと思いましたが、それではうまくいきませんか?

投稿2017/01/25 05:50

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/01/25 06:06

lock(score)だとlock対象がdictionaryになってしまう気がして、lock(score[stype])だと値型なのでlockされない気がしていますちょっと試してみますね。
Zuishin

2017/01/25 06:22

いえ、lock(node)ではダメですか?
退会済みユーザー

退会済みユーザー

2017/01/25 09:55 編集

あぁなるほどですね。再帰計算時にnodeをロックするってことですね。ありがとうございます!確かにそれでいけそうな気がします。うまくいったらベストアンサーとさせていただきます。 ただ思ったのですが、nodeごとロックしてしまうとscoretype毎の計算が並列化できないのでそこは厳しそうですかね。 追記 分岐点のノードの情報を持ってればPLINQでロックすれば解決しました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問