Lazy <T>: «Для оценки функции требуются все потоки» - PullRequest
17 голосов
/ 16 декабря 2010

У меня есть статический класс с некоторыми статическими свойствами. Я инициализировал их все в статическом конструкторе, но потом понял, что это расточительно, и я должен лениво загружать каждое свойство при необходимости. Поэтому я переключился на использование типа 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>. При развертывании узла визуализатора отладчика фактического объекта Lazy<T> свойство Value просто отображает null без каких-либо сообщений.

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

Ответы [ 5 ]

15 голосов
/ 16 декабря 2010

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

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

...

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

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

РЕДАКТИРОВАТЬ: Я думаю, что я наткнулся на ответ при рассмотрении Lazy<T> под ILSpy (по совершенно другой причине). Получатель свойства Value имеет вызов Debugger.NotifyOfCrossThreadDependency(). У MSDN есть это, чтобы сказать:

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

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

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

1 голос
/ 16 декабря 2010

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

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

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

Взгляните на Гейзенбаг

0 голосов
/ 06 сентября 2018

Для меня я обнаружил, что не имеет значения, был ли у меня this.Configuration.LazyLoadingEnabled = false; или = true;, была ли у меня строка в моем DBContext или нет.Похоже, это происходит из-за того, что я прочитал о проблеме, потому что возникает поток, и отладчик хочет разрешения запустить его / предупреждает вас, прежде чем он подстегнет его.По-видимому, в некоторых случаях вы можете даже позволить ему продолжать работу в соответствии с ответом MUG4N здесь: Visual Studio во время отладки: для оценки функции требуется, чтобы все потоки выполнялись

Но я обнаружил, что яможно обойти проблему.

2 варианта:

  1. Добавьте .ToList() на свой Queues:

    var q = db.Queues.OrderBy(e => e.Distributor).ToList();

  2. Я нашел обходной путь, выбрав Непубличные участники> _internalQuery> ObjectQuery> Просмотр результатов.

enter image description here

0 голосов
/ 16 февраля 2018

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

Я сделал две вещи изначально неправильно. Я не правильно определил первичный ключ в своей сущности 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");
}
0 голосов
/ 12 ноября 2015

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

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

...