lazy :「関数評価では、すべてのスレッドを実行する必要があります」
-
10-10-2019 - |
質問
いくつかの静的特性を備えた静的クラスがあります。それらすべてを静的コンストラクターで初期化しましたが、それが無駄であることに気付き、必要に応じて各プロパティを怠zy-ロードする必要があることに気付きました。そこで、使用に切り替えました System.Lazy<T>
すべての汚い作業を行うためにタイプし、私の場合は実行された場合は常に単一のスレッドがあったため、スレッドの安全機能を使用しないように指示しました。
私は次のクラスになりました:
public static class Queues
{
private static readonly Lazy<Queue> g_Parser = new Lazy<Queue>(() => new Queue(Config.ParserQueueName), false);
private static readonly Lazy<Queue> g_Distributor = new Lazy<Queue>(() => new Queue(Config.DistributorQueueName), false);
private static readonly Lazy<Queue> g_ConsumerAdapter = new Lazy<Queue>(() => new Queue(Config.ConsumerAdaptorQueueName), false);
public static Queue Parser { get { return g_Parser.Value; } }
public static Queue Distributor { get { return g_Distributor.Value; } }
public static Queue ConsumerAdapter { get { return g_ConsumerAdapter.Value; } }
}
デバッグ時に、私が見たことのないメッセージに気づきました:
関数評価では、すべてのスレッドを実行する必要があります
使用する前 Lazy<T>
, 、値が直接表示されました。次に、スレッドアイコンのある丸いボタンをクリックして、怠zyな値を評価する必要があります。これは、取得している私のプロパティでのみ発生します .Value
の Lazy<T>
. 。実際のデバッガービジュアライザーノードを拡張するとき Lazy<T>
オブジェクト、 Value
プロパティは単に表示されます null
, 、メッセージなし。
そのメッセージは何を意味し、なぜ私の場合に表示されているのですか?
解決
題されたMSDNページを見つけました」方法:時計値を更新します「それを説明する:
デバッガーで式を評価すると、2つの更新アイコンの1つが値列に表示される場合があります。 1つの更新アイコンは、2つの矢印を含む円で、反対方向に円を描きます。もう1つは、スレッドに似た2つの波状の線を含む円です。
...
2つのスレッドが表示された場合、潜在的なクロススレッド依存性のために式は評価されませんでした。クロススレッド依存関係とは、コードを評価するには、アプリケーション内の他のスレッドが一時的に実行される必要があることを意味します。 ブレークモードの場合、アプリケーション内のすべてのスレッドは通常停止されます。他のスレッドが一時的に実行できるようにすると、プログラムの状態に予期しない影響を与える可能性があり、デバッガーがブレークポイントなどのイベントを無視します。
誰かがそれを与えることができるなら、私はまだより良い説明が欲しいです。これが答えない質問には次のことが含まれます。すべてのスレッドが実行する必要がありますか?デバッガーはそのようなケースをどのように識別しますか?スレッドの更新アイコンをクリックすると、正確に何が起こりますか?
編集: 調べたときに答えに出くわしたと思います Lazy<T>
下 ilspy (まったく異なる理由で)。のゲッター Value
プロパティにはaの呼び出しがあります Debugger.NotifyOfCrossThreadDependency()
. 。 MSDNにはこれがあります:
...]機能評価を実行するには、通常、評価を実行しているスレッドを除くすべてのスレッドを凍結する必要があります。リモートシナリオで発生する可能性があるように、関数評価で複数のスレッドで実行が必要な場合、評価はブロックされます。 notifyofcrossthread -dependency通知は、デバッガーにスレッドをリリースするか、関数評価を中止する必要があることを通知します。
したがって、基本的には、いくつかの表現を評価しようとする迷惑なケースを防ぐために、ビジュアルスタジオは30秒間ぶら下がっていて、「関数評価がタイムアウトした」ことを知らせます。評価が成功するための他のスレッドまたはその他の方法で、評価は永遠にブロックされます。
他のスレッドを実行するとデバッグセッションが中断される可能性があるため、通常の式を評価すると、他のすべてのスレッドが凍結されたままになります。デバッガーは自動的にプロシードされず、ウサギの穴を飛び降りる前に警告します。
他のヒント
私の推測では、デバッガーが避けようとしていると思います 影響を与える アプリケーションは、プロパティをロードして状態にします。
怠zyな負荷は、プロパティを参照/アクセスする場合にのみ発生することを覚えておく必要があります。
これで、一般的に、デバッグがアプリケーションの状態に影響を与えることは望ましくありません。そうしないと、アプリケーション状態がどうあるべきかを正確に表現しません(マルチスレッドアプリケーションとデバッグを考えてください)
見て heisenbug
ローカル変数を作成し、検査する値を割り当てます。
これにより、デバッガーがプロパティにアクセスするかどうかを心配する必要がないため、それを検査できます。これは、プロパティがアプリケーションを妨害するかどうかを心配する必要がないためです。
私はこれに何時間も苦労し、すべてのスレッドが誤解を招くように要求することについての元のエラーメッセージを見つけました。新しいソリューションから既存のデータベースにアクセスし、新しいソリューションを作成していました Entity Framework
実在物 POCO
新しいソリューション内のsおよびデータアクセスレイヤーにアクセスして、 DB
.
私は最初に2つのことをしました。私は自分のc#エンティティの主キーを適切に定義しませんでした POCO
, 、 そしてその table
私はアクセスしていました DB
(そうではありませんでした dbo.tablename
しかし edi.tablename
).
私の中で DbContext.cs
ファイル、私は正しいスキーマの下にテーブルをマッピングするために次のことをしました。これらのことを修正すると、エラーがなくなり、うまくいきました。
protected override void OnModelCreating(DbModelBuilder dbModelBuilder)
{
base.OnModelCreating(dbModelBuilder);
dbModelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
dbModelBuilder.Entity<TableName>().ToTable("TableName", schemaName: "EDI");
}
私にとって、私が持っていたかどうかは問題ではないことがわかりました this.Configuration.LazyLoadingEnabled = false;
また = true;
, 、DBContextにラインがあったかどうか。スレッドが発生しており、デバッガーはそれを実行する許可を望んでいるため、問題を読んでから発生するようです。どうやら、場合によっては、ここでMUG4Nの回答に従って続行することもできます。 デバッグ中のビジュアルスタジオ:関数評価では、すべてのスレッドを実行する必要があります
しかし、私が見つけたのは、問題を回避できることでした。
2つのオプション:
追加
.ToList()
あなたにQueues
:var q = db.Queues.OrderBy(e => e.Distributor).ToList();
非公開のメンバーを選択して回避策を見つけました> _internalquery> objectquery>結果ビュー。