18

EF6 とその Async 関数のテストを開始したところです。それらがスレッドセーフではないことに気付いたとき、少年は驚きました。それがポイントだと思いました。

私はTask何年も前から独自の拡張メソッドを持っていましたが、私が EF から待っていたのは、それらをスレッド セーフにすることでした。

少なくとも私のタスクベースの機能lockは、互いに干渉しないように編集されました。EF6はそこまで行きません。しかし、主な問題は、私のコードが彼らのコードと共有しているものです。つまり、非同期クエリを発行してから、完了する前に、遅延読み込みをトリガーするナビゲーション プロパティ (同じコンテキストで事前に読み込まれた完全に別のエンティティ) へのアクセスを試みます。これは、UI、即時関数以外の他のコード、またはその他の多数のシナリオによってトリガーされる可能性があります。

私の知る限り。dbContext で (エンティティ間で) 共有される可変リソースは、接続と変更追跡 (キャッシュ) の 2 つだけです。それらの周りにロックを機能に追加できれば、スレッドセーフなコンテキストが得られます。

2段階で行うこともできます。データベースのクエリに使用される 1 つの集中型関数をロックするプロバイダーを実装できれば。非エンティティ (匿名) オブジェクトを返すか、AsNoTracking() を呼び出すことによって、追跡されていないクエリはスレッド セーフになり、別のスレッドが遅延ロードされたオブジェクトを要求している場合でも、Async 関数で安全に呼び出すことができます。

スレッドごとに 1 つのコンテキストを使用する必要があるため、スケーラビリティはそれほど悪くはありません。少しの並列処理を導入するために await を 1 つでもスキップしようとすると、非同期関数でさえテーブルから外れます。待機中の関数がタスクで返されるとトリガーされる可能性のあるシステム (wpf など)。

だから私の質問はです。このようなプロバイダーを実装した人はいますか。それとも、私と一緒に仕事をしてくれる人はいますか?

4

1 に答える 1

9

建築上の問題に直面していると思います。あなたが説明しているのは、UI が EF オブジェクトを直接使用するアプリケーションであり、「関心の分離」パラダイムを破っています。

私の側では、カスタム スレッドセーフ キャッシュをモデル レイヤーで使用し、すべてがモデル レイヤーで行われるようにします。よく知られている AsyncLock を使用して、キャッシュにスレッド セーフを実装しました。

DbContext オブジェクト、およびすべての EF CRUD 関連操作の有効期間は非常に限られています。各 CRUD 操作は、独自の DbContext をインスタンス化し、モデル オブジェクトをキャッシュに返します。その後、コンテキストがガベージ コレクションされます。私のアプリケーションはキャッシュを抽象化レイヤーとして使用し、キャッシュは EF を DB 抽象化レイヤーとして使用します。

たとえば、オブジェクトの添付プロパティの探索は、モデル レイヤーにカスタム メソッドを実装することによって行われます。これは、オブジェクト ID をパラメーターとして取り、関連するオブジェクトのリストをキャッシュに返します。UI がキャッシュに要求し、次にキャッシュが EF に要求し、利用可能になると、キャッシュに対して行われた呼び出しによってオブジェクトが UI に返されます。そのような単純な。

EntityFramework はスレッド セーフになるように設計されていないため、マルチスレッドで操作する方法はありません。( EFスレッドセーフ)

DbContext に並列アクセスする代わりに、マルチスレッドでアクセスできるモデル レイヤーを構築する必要があります。また、モデルは DB に対して複数の並列呼び出しを行うことができますが、各呼び出しはインスタンス化して独自の DbContext を保持する必要があることに注意してください。各呼び出しの最後に、関連する DbContext を破棄する必要があります。

DbContext はインスタンス化が非常に高速ですが、唯一の欠点はネットワークの待ち時間です。そのため、メモリ キャッシュを使用することをお勧めします。

于 2015-01-28T16:04:51.667 に答える