Классическая сцена из жизни любого владельца компьютера: машина подтормаживает, курсор задумывается, окна сопротивляются, и вы с сердитым нажимом вызываете диспетчер задач, чтобы наконец увидеть виновника. Экран загорается, и перед вами почтенная тишина: процессор свободен, диск мирно мурлычет, все процессы стоят по стойке смирно. Стоит закрыть окно мониторинга, и тормоза возвращаются. Ни одна шуточная формулировка не передаёт это чувство лучше, чем термин из профессионального жаргона: гейзенбаг, ошибка, которая меняет поведение или исчезает всякий раз, когда вы пытаетесь на неё посмотреть. За иронией названия скрывается совершенно серьёзный закон измеримой техники, и разобраться в нём - значит перестать бояться странностей своего компьютера.

Откуда взялось чудное слово и что оно значит

Термин гейзенбаг это шутливое приветствие в сторону Вернера Гейзенберга, физика, сформулировавшего принцип неопределённости, и более точную бытовую идею эффекта наблюдателя: необходимость измерять вмешивается в измеряемое. Инженеры электроники знали ясную физическую версию этого принципа задолго до программистов: подключаешь щуп осциллографа к схеме, и сам щуп начинает менять поведение схемы, этот эффект так и называется эффектом пробника.

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

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

Почему диспетчер задач лечит замедление

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

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

Во-вторых, и это любопытнее, само системное мониторирование влияет на расписание операционной системы. Windows платит внимание тому, какое окно находится на переднем плане, и приподнимает приоритет его потоков перед фоновыми приятелями: приложение, видимое вами, получает маленькую, но заметную фору. Диспетчер задач, появляясь на переднем плане, становится почётным гостем процессорного времени, и его отзывчивость создаёт приятную видимость того, что "всё наладилось".

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

Как гейзенбаги разыгрываются в отладке программ

У разработчиков явление принимает более изощрённые формы, и книги по инженерии полны историй о них. Классика жанра - ошибка, проявляющаяся только в оптимизированной сборке. Компилятор с хорошей оптимизацией разматывает циклы, держит переменные в регистрах, переставляет инструкции; версия для отладки делает всё по-честному и неспеша, и ошибка в ней не воспроизводится никогда. Отладка становится ловлей неуловимого сбоя: программа под наблюдением послушна, а в реальном мире бунтует.

Другой знаменитый источник - гонки потоков. Ошибка возникает, когда два потока наперегонки хватают общие данные, и обычно порядок столкновения решается наносекундами. Стоит вывести журнальную строку или поставить точку останова, и расписание потоков меняется настолько, что гонки дружелюбно расходятся. Гейзенбаг тут приобретает почти осязаемую форму: меряешь - меняется, меряешь снова - исчезает совсем.

Третий вид связан с неинициализированной памятью и неправильными указателями. В отладочной конфигурации память часто заранее подчёркивается определёнными значениями, и программа ведёт себя шаблонно предсказуемо; в боевой сборке память достаётся со старой мусорной живописью, и поведение выходит совсем иным. Люди не зря изобрели эпитет "зловещие нехватки внимания": инициализация переменных в пылу отладки заменяется их тихим обнулением для удобства наблюдателя, и ошибка тут же исчезает из виду.

Как профессионалы ловят блуждающие ошибки

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

  1. Заменяйте активный отладчик пассивным наблюдением: журналирование в память с редкими появлениями на диске меняет системный ритм гораздо меньше, чем точки останова;
  2. Уменьшайте вмешательство из отладочной сборки постепенно: включайте оптимизации фрагментами и смотрите, на каком уровне ошибка возвращается;
  3. Измеряйте, не дыша: профилировщики с малым вмешательством и сборы статистики позволяют подсматривать за системой не наступая на неё;
  4. Учите программу самосвидетельствовать: аккуратные журналы, удобные дампы при сбоях и трассировка в реальном времени надёжнее, чем ручное стояние рядом с клавишей F5;
  5. Допускайте существование странных багов и не требуйте у них немедленного воспроизведения: гейзенбаг охотнее ловится повторением, а не заточением в лаборатории.

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

Что вся эта история зеркалит об устройстве мира техники

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

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

Бытовые разновидности наблюдательского эффекта вокруг компьютера

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

Есть и менее анекдотичная польза такого знания для домашнего технического опыта. Если машина тормозит время от времени, помогает не пытаться изловить всплеск вручную, а организовать долгосрочное наблюдение: ведение мониторинга с записью в фон, аккуратные отметки времени, когда замедление случается, заметки об открытых в тот момент вещах. Не гонитесь за вспышкой с факелом, поставьте по тропе фотоловушку. Такое терпение почти всегда оказывается производительнее, чем вдохновенные поиски виновника на горячую голову.

Позиция силы у того, кто знает про наблюдение

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

Короткая энциклопедия соседей гейзенбага.

Стоит одной строфой увековечить и родственные измышления жаргона, без которых картина была бы неполной. Борбаг назвали в честь датского учёного Нильса Бора: это честная, воспроизводимая и на редкость упрямая ошибка, повторяющаяся всякий раз при одних и тех же условиях - подарок для инженера после всех невидимок предыдущих абзацев. Шрёдинбаг появляется тогда, когда программа на удивление работает, пока никто не заметит, что у неё внутри кроется нечто принципиально невозможное: с этого момента она работать отказывается принципиально. Мандельбаг обязан своим именем фракталам и означает ошибку, у которой внутри причины сидит другая причина, а внутри той - ещё одна. Юмор этих названий имеет серьёзное применение: навесив ярлык на баг, команда получает возможность серьёзно рассуждать о его природе, не тратя часов на общие описания.

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

Закрытие кабинета наблюдений.

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

И в следующий раз, когда открытый монитор задач прогоняет тормоза как хозяйский свист, не спешите считать это совпадением или необъяснимой причудой. Где-то под этой картинкой стоят и фоновые службы с их уставшим расписанием, и передний план с его маленьким бонусом приоритета, и тормозной всплеск, уже угасший ещё до прихода свидетеля. Признать это значит увидеть в компьютере не капризный характер, а тонкий механизм, чувствительный даже к вашему взгляду.