Большинство оконных приложений — это недоработанные real-time приложения

в 13:00, , рубрики: linux, MacOS, ruvds_перевод, UI, windows, быстродействие приложений, разработка приложений

Большинство оконных приложений — это недоработанные real-time приложения - 1


В оконных приложениях таких платформ, как Windows, Linux и macOS, скрывается ряд недоработок, которые порой снижают их быстродействие до раздражающе медленного. Сюда относятся нюансы работы в реальном времени, блокирование памяти при доступе к диску и недостаточно эффективное планирование для активного оконного приложения. В статье мы подробно разберём все эти проблемы.

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

Вскоре после начала я столкнулся с проблемой, которая требовала обеспечить невозможность переполнения очереди событий ввода. По сути, эта задача сводится к тому, чтобы каждый обработчик событий не выполнялся дольше некой максимальной продолжительности времени. Затем меня осенило! Я уже слышал это раньше — «максимальная продолжительность времени», так как занимаюсь разработкой систем, работающих в реальном времени.

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

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

Когда я кликаю кнопкой мыши, нажимаю клавишу клавиатуры, то ожидаю, что система отреагирует в течение ограниченного промежутка времени. Ограниченный промежуток времени? Мы это уже слышали! Оконные приложения тоже являются системами реального времени. А ограниченное количество времени – это сколько, 100 мс или, может, 250мс? Главный смысл здесь в том, что время реакции не должно быть неопределенным. Я никогда не должен видеть вращающийся курсор ожидания. Никогда.

▍ Библиотечные функции не являются real-time

Одна из фундаментальных проблем в том, что многие оконные приложения для Windows, Linux и macOS вызывают функции, которые не предназначены для выполнения в течение ограниченного промежутка времени. Вот простой пример: многие приложения не думают дважды, выполняя ввод-вывод файла в обработчике событий UI. На стандартных дисках в большинстве случаев это приводит к терпимой задержке, но что если файл хранится на сетевом винчестере? Для обработки запроса такого файла может потребоваться гораздо больше секунды. Это приведет к временному зависанию приложения и недопониманию пользователя. Сетевой диск работает корректно, но оконное приложение нет.

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

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

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

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

▍ Виртуальная память

Что касается Windows, Linux и macOS, то эти операционные системы используют виртуальную память. Когда приложения выделяют область памяти, фактически они выделяют не физическую память. Они говорят операционной системе, что будут использовать определённую область памяти для конкретной цели. Это раскрывает богатую функциональность, но, в частности, позволяет операционным системам экономить физическую память, прозрачно сохраняя её страницы на жёстком диске и восстанавливая нужную страницу, когда приложение снова к ней обращается. Это означает, что при доступе к жёсткому диску доступ к памяти может блокироваться.

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

Это не является типичной проблемой, но случаи, когда вся система «исчерпывает память» встречаются довольно часто. Оказавшись в таком состоянии, система начинает спешно подкачивать страницы памяти на жёсткий диск. Это влияет на оконные приложения и ведёт к тому, что система зависает без предупреждения и без какого-либо способа вмешаться в этот процесс, поскольку нажатия клавиш не обрабатываются. С позиции пользователя это выглядит хуже, чем паника ядра. Такой тип сбоя происходил у меня в Linux много раз, поэтому я знаю, что это реальная проблема. Возможно, разработчики Windows и macOS уже её учли, но я в этом сомневаюсь.

Есть ли возможность её исправить? По крайней мере, в Linux есть семейство функций mlock(), которые просят операционную систему помещать и удерживать страницы памяти процесса в RAM. В Windows и macOS наверняка присутствуют аналогичные функции. Естественно, здесь есть и сложности, например, кто отвечает за блокирование страниц памяти – приложение или операционная система? Откуда приложение знает, какие страницы блокировать? Откуда это знает операционная система?

▍ Планирование в реальном времени

Последняя фундаментальная проблема реализации real-time UI поверх современных платформ – это отсутствие планирования для активного оконного приложения. Это системы с разделением времени, то есть выполнение процесса может быть приостановлено на произвольно долгий промежуток времени, если за использование CPU соперничает множество старых процессов.

Представьте, что у вас есть фоновые процессы, занимающие 100% CPU, и тут поступает событие для активного приложения. Операционная система может заблокироваться на 100 мс или более, прежде чем позволит этому приложению обработать поступившее событие. Это может вызвать задержку ответа для пользователя, нарушающую ограничение реального времени (примечание: типичным временным срезом в системах с разделением времени является 10 Гц).

Но для этого тоже есть решение, менеджер окон или нечто подобное, может просить ОС выдать приоритет в расписании требующему того приложению. Это означает, что в период, когда приложение активно и требует CPU, фоновые процессы голодают. Правда, есть сложности с применением этого решения к существующим системам, например, «Что делать, когда активное оконное приложение входит в бесконечный цикл?», «А что насчёт многопроцессных приложений?»

▍ Заключение

Надеюсь, мне удалось убедить вас, что в основе передовых оконных приложений есть недоработки. Работают ли эти приложения? Конечно, бо́льшую часть времени такие приложения исправно работают, но когда дают сбой из-за неудачных допущений относительно реального времени, это прям бесит. В этом случае мы наблюдаем вращающийся курсор ожидания. Для интерактивных систем рабочих станций такое поведение неприемлемо. Я хочу использовать отзывчивые, корректные приложения. В будущем UI будут учитывать ограничения реального времени во всём используемом в них стеке.

Насколько я знаю, исправление этих проблем рациональным способом потребует больших изменений на уровне экосистемы и общего осведомления разработчиков. За десятилетия скопилось много широко распространённых архитектурных решений, в которых эти проблемы игнорируются. Меня тянет отказаться от использования Windows, macOS и Linux в качестве основных платформ, с которыми я взаимодействую.

Telegram-канал с розыгрышами призов, новостями IT и постами о ретроиграх 🕹️

Автор: Дмитрий Брайт

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js