it-swarm.com.ru

Ленивый <T>: «Оценка функции требует запуска всех потоков»

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

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

17
Allon Guralnek

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

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

...

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

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

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

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

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

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

15
Allon Guralnek

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

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

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

Посмотрите на Heisenbug

1
Adriaan Stander

Я боролся с этим в течение нескольких часов и нашел первоначальное сообщение об ошибке, требующее, чтобы все потоки запускались в заблуждение. Я получал доступ к существующей базе данных из нового решения и создавал новые Entity Framework сущность POCOs и слои доступа к данным в новом решении для доступа и сопоставления с 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
Steelpaddy

Для меня я обнаружил, что не имеет значения, был ли у меня 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
vapcguy

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

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

0
Matt Knowles