Подтвердить что ты не робот

Lazy <T>: "Для оценки функции требуется, чтобы все потоки выполнялись"

У меня есть статический класс с некоторыми статическими свойствами. Я инициализировал их все в статическом конструкторе, но потом понял, что это расточительно, и я должен lazy-load каждое свойство, когда это необходимо. Поэтому я переключился на использование типа 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; } }
}

При отладке я заметил сообщение, которое я никогда не видел:

Для оценки функции требуется, чтобы все потоки выполнялись

enter image description here

Перед использованием Lazy<T> значения отображаются непосредственно. Теперь мне нужно щелкнуть по круглой кнопке с иконкой ниток, чтобы оценить ленивое значение. Это происходит только по моим свойствам, которые извлекают .Value из Lazy<T>. При расширении визуализатора отладки node фактического объекта Lazy<T> свойство Value просто отображает null без какого-либо сообщения.

Что означает это сообщение и почему оно отображается в моем случае?

4b9b3361

Ответ 1

Я нашел страницу MSDN под названием " Как: Обновить значения часов", объясняя это:

Когда вы оцениваете выражение в отладчике, в столбце Значение может появиться один из двух значков обновления. Один значок обновления - это круг, содержащий две стрелки, которые пересекаются в противоположных направлениях. Другой - это круг, который содержит две волнистые линии, которые напоминают потоки.

...

Если появляются два потока, выражение не оценивалось из-за потенциальной зависимости между потоками. Зависимость между потоками означает, что для оценки кода требуется, чтобы другие потоки в вашем приложении выполнялись временно.. Когда вы находитесь в режиме прерывания, все потоки в вашем приложении обычно останавливаются. Разрешить запуск других потоков временно может привести к неожиданным последствиям для состояния вашей программы и заставляет отладчик игнорировать такие события, как точки останова.

Мне все же хотелось бы получить лучшее объяснение, если кто-нибудь сможет это дать. Вопросы, на которые это не отвечает, включают: Какая оценка требует, чтобы все потоки выполнялись? Как отладчик идентифицирует такой случай? Что именно происходит, когда вы нажимаете значок обновления потока?

EDIT: Я думаю, что наткнулся на ответ, рассматривая Lazy<T> под ILSpy ( по совершенно другой причине). Получатель свойства Value имеет вызов Debugger.NotifyOfCrossThreadDependency(). MSDN говорит следующее:

[...] выполнение оценки функции обычно требует замораживания всех потоков, за исключением потока, который выполняет оценку. Если для оценки функции требуется выполнение более чем одного потока, как это может происходить в сценариях удаленных операций, оценка будет блокирована. Уведомление NotifyOfCrossThreadDependency сообщает отладчику, что он должен освободить поток или прервать оценку функции.

В основном, чтобы предотвратить раздражающий случай, когда вы пытаетесь оценить какое-то выражение, а Visual Studio просто зависает в течение 30 секунд, а затем информирует вас о том, что "функция оценки имеет тайм-аут", код имеет возможность сообщить отладчику, что он должен разморозить другие потоки для успешной оценки или иначе оценка будет заблокирована навсегда.

Так как запуск других потоков может привести к нарушению сеанса отладки, как обычно, когда вы оцениваете выражение, все остальные потоки остаются замороженными, отладчик автоматически не запускает и не предупреждает вас, прежде чем позволить вам спрыгнуть в кроличью нору.

Ответ 2

Я предполагаю, что отладчик пытается не влиять на состояние приложения, загружая свойства для вас.

Вы должны помнить, что ленивая нагрузка происходит только при ссылке/доступе к свойствам.

Теперь, в общем, вы не хотите, чтобы отладка влияла на состояние приложения, в противном случае это не даст точное представление о состоянии приложения (подумайте о многопоточных апликации и отладке)

Посмотрите Heisenbug

Ответ 3

Создайте локальную переменную и присвойте ей значение, которое вы хотите проверить.

Это позволит вам проверить его, потому что отладчику не нужно беспокоиться о том, будет ли доступ к свойству нарушать ваше приложение, потому что он уже обратился к нему при назначении его локальной переменной.

Ответ 4

Я боролся с этим в течение нескольких часов и нашел исходное сообщение об ошибке, требующее, чтобы все потоки запускались в заблуждение. Я обращался к существующей базе данных из нового решения и создавал новый объект Entity Framework POCO и уровни доступа к данным в новом решении для доступа и сопоставления с DB.

Я сделал две вещи изначально неправильно. Я не правильно определил первичный ключ в моей сущности С# 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");
}