1

大きな XML ドキュメントを読み取り、C# オブジェクトのリストを生成するヘルパー クラスがあります。

私はこれらのオブジェクトをかなり頻繁に扱っているので、これを行う最善の方法は、メモリに保存してそこからアクセスすることだと思いました。

メモリからオブジェクトを取得する単純なリポジトリを作成し、存在しない場合は追加します。

リポジトリは次のようになります。

public class XmlDocumentRepository
{
    private readonly ICacheStorage _cacheStorage;
    public XmlDocumentRepository(ICacheStorage cacheStorage)
    {
        _cacheStorage = cacheStorage;
    }

    private readonly object _locker = new object();

    private void DeserializeXmlDocument()
    {
        lock (_locker)
        {
            // I deserialize the xml document, i generate the c# classes, and save them in cache
            IEnumerable<Page> pages = new XmlDeserializerHelper().DeserializeXml();    

            foreach(var page in pages)
            {
                _cacheStorage.Add(page_Id, page);
            }
        }
    }

    public Page GetPage(Guid page_Id)
    {
        Page page = _cacheStorage.Get<Page>(page_Id);
        if (page != null)
            return page;

        lock (_locker)
        {
            page = _cacheStorage.Get<Page>(page_Id);
            if (page != null)
                return page;

            DeserializeXmlDocument();

            page = _cacheStorage.Get<Page>(page_Id);
            return page;
        }
    }
}

XmlDocumentRepositoryWeb アプリケーション内で使用されます (より正確には asp.net mvc)。

リポジトリの実装は適切ですか? lockステートメントを適切に使用していますか?

4

2 に答える 2

1

質問に対する私のコメントで、私はキャッシュが共有されていると誤解しました。次のいずれかのオプションを実行する必要があると思います。

  • XmlDocumentRepositoryロックオブジェクトはプライベートフィールドであるため、すべてのリクエストで使用されるシングルトンを作成します。これにより、各リクエストには、新しいフィールドを持つリポジトリの新しいインスタンスが含まれます。
  • ロックオブジェクトを静的フィールドにして、すべてのXmlDocumentRepositoryインスタンスで共有されるようにします。
于 2013-03-06T13:02:08.907 に答える
0

原則として、複数のスレッドで使用されるデータ ストアへのすべてのアクセス バリエーションを保護する必要があります。あなたの実装には潜在的な問題がいくつかあります。

1: ICacheStorage は外部から提供されます。これは、このコレクションが他の場所で変更される可能性があることを意味し、ロックによって保護されている場合とされていない場合があります。おそらく、コレクション自体が内部でロックを使用すること、または他のタイプのスレッド セーフ メカニズムを使用することを要求する必要がありますか?

2: データ アクセスのロック保護に一貫性がありません。GetPage ではロックを適用する前に _cacheStorage にアクセスしますが、Deserialize ではロック内でアクセスします。これは、一方がキャッシュに追加している間に、もう一方がキャッシュから取得しているという結果が得られる可能性があることを意味します。

3: キャッシュ、xml の読み取り、またはその両方にスレッド セーフが必要ですか? キャッシュのみを保護する必要がある場合は、xml の読み取りをロックの外に移動します。両方を保護する場合は、GetPage 関数全体をロック内に配置する必要があります。

于 2013-03-06T12:38:58.310 に答える