2015-12-04 6 views
13

マップをクリアする前にオブジェクトをリリースしなければならないマップがあります。私は地図上を反復し、オブジェクトを削除/解放したいと思っています。マップを反復処理する唯一の方法は、私は複数のプロデューサおよび複数のコンシューマ同期する方法を、範囲であるので、ここでGolang同時マップアクセス

はモックアップ例 https://play.golang.org/p/kAtPoUgMsq

のですか?

私はそれは不可能反復中にキーを変更/削除するだろうので、マップをロック読みたくありません。

+0

これを処理するには、さらに多くのコンテキストが必要です。地図には何が入っていますか?それは巨大ですか?どのくらい速く物をリリースしていますか? (何がリリースされますか?)リリースされたオブジェクトが別のゴルーチンによって使用されている場合、それは災害ですか?そうであれば、マップから選択されたオブジェクトがどれだけ長く使用されているかを決定します。アプリケーションとは何ですか?また、優先順位は何ですか(スループットを最大化して待ち時間を制限するなど)。 – twotwotwo

答えて

4

あなたは、複数のオブジェクトのリリースが同時に起こるなど、すべての要件を述べていませんが、私が考えることができる最も簡単な解決策は、要素を削除し、削除された要素ごとにリリースゴルーチンを起動することです。

for key := range keysToRemove { 
    if v, ok := m[k]; ok { 
     delete(m, k) 
     go release(k, v) 
    } 
} 
+0

この回答に記載されている方法で実際に十分ですか? (1.6の変更後のEsp!)言語仕様には、これがクリアされ/明確に回答される場所がありますか? – BadZen

+0

上記のコードサンプルでは、​​マップは単一のゴルーチンからアクセスされるため、同時アクセスはないため、同期は必要ありません。 – kostya

+0

もちろん、OPは反復中に並行ライターが存在すると想定しています。彼はこう言います。「マップをロックするのは、反復中にキーを削除/変更することが不可能なので、私はそのマップをロックしたくありません。彼が作ったのではないと言っているわけではありません。 – BadZen

2

アップデート2017年8月(golang 1.9

あなたは今syncパッケージに新しいMapタイプを持って、償却定数時間の負荷と同時にマップで店舗、および削除します。
複数のゴルーチンがMapのメソッドを同時に呼び出すことは安全です。


オリジナルの答え2016年11月

私はマップから削除は、書き込み動作と見なされているので、理にかなってマップ

をロック読みたくありません、他のすべての読み取りと書き込みでシリアル化する必要があります。これは、削除を完了するための書き込みロックを意味します。 (ソース:this answer)最悪のシナリオ(複数の作家と読者を)と仮定すると、

は、あなたがロックのボトルネックを回避するために、ため、複数sync.RWMutexを使用してRemove() methodを持ってorcaman/concurrent-mapの実装、見てみることができ、この同時マップがありますいくつかの(SHARD_COUNT)マップシャードに分割されています。
RWMutexas in this exampleを1つだけ使用するよりも高速です。

6

あなたが際どいマップアクセスなしmapから物事をクリーンアップすることができる方法の束があります。あなたのアプリケーションのために働くものは、それが何をしているかに大きく依存します。

0)地図上で作業している間は、ロックするだけです。マップのサイズがあまり大きくないか、レイテンシの許容量がある場合は、時間の点ではあなたは他のものについて考えることに移ります。後で問題になる場合は、問題に戻ってくることができます。

1)は、オブジェクトまたはポインタをコピーして、バックグラウンドでオブジェクトを解放し、ロックを保持しながら、マップをクリアします。ロック解除に時間がかかるという問題がある場合は、ロックを長時間保持しておきますが、これは簡単な回避策です。重要なことはすべて、atomic.Valueを使用し、効率的に読み取る場合

2)は、基本的にあります。これにより、1つの地図を完全に新しい地図と置き換えることができます。書き込みが本質的に作業負荷の0%である場合、効率的な読み取りはすべての変更で新しいマップを作成するコストのバランスをとります。それはまれですが、たとえばencoding/gobには、このように管理されたタイプのグローバルマップがあります。

3)必要な作業をすべて行っていない場合は、データの保存方法を調整してください(例:地図を破るなど)。あなたの地図を16の地図とハッシュキーで置き換えて、自分がどのマップに属しているかを決定し、一度に1つのシャードをクリーンアップまたは他の書き込みのためにロックすることができます。

goroutine Aはマップから何かを取得し、Bはマップをクリアして物をリリースし、Aはリリースされたものを使用します。

1つの戦略では、各値を使用または解放している間はロックします。ロックを必要としますが、グローバルなものは必要ありません。

もう1つは、レースが既知で悲惨ではない場合、レースの結果に耐えることです。たとえば、net.Connへの同時アクセスは、そのドキュメントによって明示的に許可されているため、使用中の接続を閉じると、エラーが発生する可能性がありますが、未定義のアプリケーション動作にはなりません。あなたは本当にあなたが何をしているのかを確かめなければなりません。しかし、原因はmany benign-seeming races aren'tです。

最後に、アプリケーションでは、使用中のオブジェクトがリリースされていないことを確認している可能性があります。オブジェクトには安全に保持された参照カウントがあり、未使用のオブジェクトだけが解放されます。それから、もちろん、心配する必要はありません。

これらのロックを何らかの形でチャンネルに置き換えようとするのは魅力的かもしれませんが、何の利益も得られません。 niceあなたのアプリは主に共有データではなくプロセス間のコミュニケーションの観点から考えて設計することができますが、共有データを持っている場合は別の方法で使用することはできません。共有データへの安全でないアクセスを除外するのは、ロックの対象となるものです。