バックグラウンド
定期的なデータ ダンプ (XML ファイル) を受け取り、それらを Entity Framework 5 (Code First) を使用して既存のデータベースにインポートするアプリケーションがあります。エンティティに既に存在するビジネス ルールを適用する必要があるため、インポートは BULK INSERT または BCP ではなく EF5 を介して行われます。
処理は、アプリケーション自体の CPU バウンドのようです (非常に高速で、書き込みキャッシュが有効なディスク IO サブシステムは、プロセス全体でほぼゼロのディスク待機時間を示し、SQL Server は 8% ~ 10% の CPU 時間しか示しません)。
効率を改善するために、TPL Dataflowとコンポーネントを使用してパイプラインを構築し、次のことを行いました。
Read & Parse XML file
|
V
Create entities from XML Node
|
V
Batch entities (BatchBlock, currently n=200)
|
V
Create new DbContext / insert batched entities / ctx.SaveChanges()
これを行うことでパフォーマンスが大幅に向上しますが、CPU が約 60% を超えることはありません。
分析
ある種のリソース競合を疑って、VS2012 プロファイラーのリソース競合データ (同時実行)モードを使用してプロセスを実行しました。
プロファイラーは、 Handle 2というラベルの付いたリソースに対して 52% の競合を示しています。掘り下げてみると、 Handle 2で最も競合を引き起こしているメソッドは次のとおりであることがわかります。
System.Data.Entity.Internal.InternalContext.SaveChanges()
2 位は、SaveChanges() の競合の約 40% です。
System.Data.Entity.DbSet`1.Add(!0)
質問
- Handle 2が実際に何であるか(TPL の一部、EF の一部など) を知るにはどうすればよいですか?
- EF は、個別のスレッドから個別の DbContext インスタンスへの呼び出しを調整しますか? 彼らが争っている共有リソースがあるようです。
- この場合、並列処理を改善するためにできることはありますか?
アップデート
問題の実行では、SaveChanges を呼び出すタスクの最大並列度は 12 に設定されています (以前の実行で Unbounded を含むさまざまな値を試しました)。
更新 2
Microsoft の EF チームがフィードバックを提供しています。要約については、私の回答を参照してください。