12

ConcurrentBag<T>次の .NET 4.0 フレームワークに次のようなクラスが存在することに、私は非常に興味をそそられています。

バッグは、順序が重要でない場合にオブジェクトを格納するのに役立ちます。また、セットとは異なり、バッグは複製をサポートします。

私の質問は次のとおりです。このアイデアをどのように実装できますか? 私がよく知っているほとんどのコレクションは、本質的に (ボンネットの下で) 何らかの形式の配列に相当し、その順序は「重要」ではないかもしれません、順序があります (これが、その必要がないにもかかわらず、列挙が行われる理由です)。ほとんどの場合、変更されていないコレクション ( ListQueueStackなど) を同じ順序で処理します)。

Dictionary<T, LinkedList<T>>推測する必要がある場合は、内部的には;になる可能性があることをお勧めします。しかし、キーとして任意のタイプを使用するのは意味がないことを考えると、それは実際にはかなり疑わしいようです。T

私が期待/期待しているのは、これが実際にはすでにどこかで「理解されている」確立されたオブジェクトタイプであり、この確立されたタイプを知っている誰かがそれについて教えてくれることです。これは私にとって非常に珍しいことです。実生活で理解するのは簡単ですが、開発者として使用可能なクラスに変換するのは難しい概念の 1 つです。そのため、可能性について興味があります。

編集

Bag一部の回答者は、aが内部的にハッシュテーブルの形式である可能性があることを示唆しています。これは私の最初の考えでもありましたが、この考えには 2 つの問題があることを予見しました。

  1. 問題のタイプに適したハッシュコード関数がない場合、ハッシュテーブルはそれほど役に立ちません。
  2. コレクション内のオブジェクトの「カウント」を単に追跡することは、オブジェクトを格納することと同じではありません。

Meta-Knight が示唆したように、おそらく例はこれをより明確にするでしょう:

public class ExpensiveObject() {
    private ExpensiveObject() {
        // very intense operations happening in here
    }

    public ExpensiveObject CreateExpensiveObject() {
        return new ExpensiveObject();
    }
}

static void Main() {
    var expensiveObjects = new ConcurrentBag<ExpensiveObject>();

    for (int i = 0; i < 5; i++) {
        expensiveObjects.Add(ExpensiveObject.CreateExpensiveObject());
    }

    // after this point in the code, I want to believe I have 5 new
    // expensive objects in my collection

    while (expensiveObjects.Count > 0) {
        ExpensiveObject expObj = null;
        bool objectTaken = expensiveObjects.TryTake(out expObj);
        if (objectTaken) {
            // here I THINK I am queueing a particular operation to be
            // executed on 5 separate threads for 5 separate objects,
            // but if ConcurrentBag is a hashtable then I've just received
            // the object 5 times and so I am working on the same object
            // from 5 threads at the same time!
            ThreadPool.QueueUserWorkItem(DoWorkOnExpensiveObject, expObj);
        } else {
            break;
        }
    }
}

static void DoWorkOnExpensiveObject(object obj) {
    ExpensiveObject expObj = obj as ExpensiveObject;
    if (expObj != null) {
        // some work to be done
    }
}
4

6 に答える 6

9

の詳細を見るとConcurrentBag<T>、内部的には基本的にカスタマイズされたリンク リストであることがわかります。

バッグは重複を含む可能性があり、インデックスでアクセスできないため、二重リンク リストは実装に非常に適したオプションです。これにより、挿入と削除のためにロックをかなり細かくすることができます (コレクション全体をロックする必要はなく、挿入/削除する場所の周りのノードだけをロックする必要はありません)。重複の心配がないため、ハッシュは必要ありません。これにより、二重連結リストが完璧になります。

于 2009-11-06T16:56:15.843 に答える
0

「バッグ」の概念は「マルチセット」と同義だと思います。

実装方法に興味がある場合は、オープン ソースの「Bag」/「Multiset」実装 (たまたま Java) が多数あります。

これらの実装は、必要に応じてさまざまな方法で「バッグ」を実装できることを示しています。TreeMultiset、HashMultiset、LinkedHashMultiset、ConcurrentHashMultiset の例があります。

Google コレクション
Google には多数の「MultiSet」実装があり、その 1 つが ConcurrentHashMultiset です。

Apache Commons
Apache には、多数の「バッグ」実装があります。

于 2009-11-06T17:14:47.417 に答える
0

順序は重要ではないため、ConcurrentBag はバックグラウンドでハッシュテーブルを使用して、データを高速に取得できるようにします。ただし、ハッシュセットとは異なりバッグは重複を受け入れます。おそらく、各アイテムは、アイテムが追加されたときに 1 に設定される Count プロパティとペアにすることができます。同じアイテムを 2 回目に追加する場合は、このアイテムの Count プロパティをインクリメントするだけです。

次に、カウントが 1 より大きいアイテムを削除するには、このアイテムのカウントを減らすだけです。カウントが 1 の場合、アイテムとカウントのペアをハッシュテーブルから削除します。

于 2009-11-06T17:03:36.810 に答える
0

まあ、smalltalk (Bag の概念が生まれた場所) では、コレクションは基本的にハッシュと同じですが、重複は許可されます。ただし、複製オブジェクトを保存する代わりに、各オブジェクトの参照カウントなどの「発生カウント」を維持します。ConcurrentBag が忠実な実装である場合、これが出発点になります。

于 2009-11-06T17:03:45.740 に答える