Доступно об АйТи: Почему полоса прогресса ходит неравномерно
Ну вот и я подключусь к волне постов и расскажу кое-что на этот счёт.
Кто виноват и что делать? И кому на Руси жить хорошо?
Опять для Лиги лени поставлю телегу впереди лошади.
Сначала отвечу на третий вопрос — хорошо начинающим программистам, ведь современные библиотеки позволили очень маленькой кровью, например, загружать сайт, а потом извлекать из него информацию. Чтобы загрузить страницу, можно просто исполнить программу cURL, которая есть в Windows 10 начиная с патча 1803, а в *nix — была с давних пор.
Виновато усложняющееся устройство компьютера, как аппаратное, так и программное. Например, между винчестером — зеркалом, вращающимся со скоростью болгарки — и файлом — цепочкой байтов с именем — есть аппаратный дисковый кэш, программный дисковый кэш, драйвер диска, драйвер файловой системы и файловые функции ОС.
А что делать — не знаю. Я смирился, тем более психологи показывают, что прогрессу достаточно идти вперёд, и пользователь всё поймёт.
И оглавление, снова для Лиги лени.
Иногда ей надо ходить неравномерно.
Загрузка — сложный процесс.
Обратная связь — затратная операция.
Иногда программа не может вызвать обратную связь.
Иногда обратную связь вызвать архитектурно сложно.
Пристёгивайтесь, поехали!
Иногда ей надо ходить неравномерно
Пример: торрент-клиент
Что происходит, когда мы скачиваем файл по протоколу распределённой закачки? (Считаем, что интернет хороший.)
Клиент обращается к трекеру (или бестрекерной сети), чтобы найти тех, у кого этот файл есть. И заодно сам объявляет трекеру, что мы этот файл хотим. Прогресс стоит.
Потихоньку сползаются раздающие — поползли по сети первые блоки. Прогресс разгоняется.
Скорость дошла до предела, предлагаемого нашим провайдером или найденными раздающими — прогресс идёт равномерно.
Файл скачан почти весь, докачиваются последние блоки. Часть раздающих отключаем, скорость падает — прогресс замирает на 99%.
Скачан самый слоупочный блок — всё, 100%!
И в этом случае есть вполне измеримый показатель прогресса — скачанный процент. Ему и не надо идти равномерно. Но: программа по каким-то собственным формулам может вычислять, когда закачка кончится, и тут уже всё как в дальнейших примерах.
Загрузка — сложный процесс
Пример: любая игра или инсталлятор
Пример с торрент-клиентом я уже привёл. Посмотрим, что творится в любой игре.
Загрузка из интернета — зависит как от пинга к серверу, так и от скорости этого самого интернета.
Доступ к файлам — на SSD почти мгновенный, на механическом диске — ощутимую долю секунды.
Линейное чтение файла — зависит от скорости диска.
Распаковка файла (почти всегда игра сжата каким-нибудь ZIP’ом) — тут уже действует процессор.
Передача распакованного в видеопамять — подключается видеошина.
Будь у нас компьютер с полностью стандартным железом, на манер ZX Spectrum, всё было бы понятно. Но ведь IBM стали стандартом именно потому, что имели множество разных процессоров, дисков и другой аппаратуры, от дешманских до high-end. А интернет-соединение вообще никак и нигде не стандартизировано.
Один из разработчиков сказал: «вот в этой точке мы перемещаем прогресс на 20%», что это значит? Он сидел с часиками и смотрел на отладочный вывод, и понял, что вот этот шаг отнимает примерно 20% времени. Примерно: на другой машине это может быть 10 или 30%. У разработчика — любого — есть один перекос: они пользуются мощными машинами, и потому отмеренные 20%, скорее всего, будут относиться именно к мощному компу.
А это уже личный опыт. Загрузку игры на Java ME я делил на 10–20 примерно одинаковых шажков. Это могла быть загрузка графики, тригонометрических таблиц, спрайтовых таблиц и много чего ещё. Показывается заставка разработчика/распространителя — игра грузится, но прогресса пока нет. Показывается заставка игры — прикидываем процент загрузки, и делаем одно из трёх.
Игра под заведомо быстрый мобильник (Nokia Series 40, Sony Ericsson серий K и Z) — нет индикатора. В таких портах на заставке даже нет места под индикатор.
Игра прикидывает, что загрузка закончится за те минимум 2,5 секунды, что отданы на заставку — тоже нет индикатора.
Или всё-таки рисует индикатор, но он идёт от 0 до 100%, даже если за время первой заставки игра ухитрилась проскочить 4 шажка из 12. Если оставшиеся восемь проскочила со скоростью звука — всё равно заставка висит минимум 2,5 секунды, с прогрессом 100%.
Обратная связь по прогрессу — затратная операция
Когда я пришёл в ту контору, писавшую игры для мобильников, их игры могли грузиться минуту и более. На Nokia Series 60, которая тогда была базовым портом! Перестав дёргать прогресс без нужды, мы ту же S60 отнесли к «условно быстрым» — какие-то телефоны ухитрялись всё загружать за пять-шесть секунд заставок, какие-то чуть дольше.
Давайте о том, как можно обеспечить обратную связь на ПК под управлением Windows (о других ОС не знаю).
Самый технически простой. Ничего не делать, только грузить, иногда на короткие моменты передавая управление главному окну. Грузит и рисует полностью последовательно: пока окно перерисовывается, загрузка не идёт. Игра выглядит «застрявшей», не реагирует на управление, ОС может даже сказать: программа не отвечает, хотите дождаться?
Одно ядро процессора полностью занято интерфейсом — программа уже реагирует на клавиатуру и мышь. А второе, загрузчик, также время от времени приостанавливается, пока главный не скажет: «У меня есть свободное время» — и не обновит информацию о прогрессе. По времени мало чем лучше первого: грузит и рисует почти последовательно.
Этот способ самый сложный, но и самый быстрый. Загрузчик кладёт информацию в «почтовый ящик». Главное ядро время от времени этот ящик трясёт — и выводит его содержимое. Если в ящике всего одна цифра, это очень просто — 4 или 8 байт, в зависимости от архитектуры процессора, перейдут от процессора к процессору неиспорченными. Но с более сложной отладочной информацией надо неплохо так заморочиться, чтобы этой порчи не было — и чтобы не было того, что грузит и рисует последовательно (см. 2).
💽 грузить, 🖌️ рисовать, ⚙️ отрабатывать сообщения Windows, ⬛ обмен данными, 🚬🎋 простаивать
Иногда программа не может вызвать обратную связь
Пример: копирование в Windows на флэшку
Просто не может, и точка. Из чужих библиотек — каких-нибудь закачек, распаковок или математики — обратную связь вызвать очень сложно (придётся их дописывать), из системных вызовов — вообще нельзя.
Чем отличается копирование на винчестер (нет защиты от небезопасного извлечения) от копирования на флэшку (таковая есть)? Последним шагом, закрытием файла! Если копирование на винчестер, пользователь уже получил управление, но Windows ещё несколько секунд трещит, сбрасывая данные на диск — на флэшке сброс идёт сразу при закрытии, ведь надо защитить флэшку от небезопасного извлечения! Минуту, без всякой обратной связи.
Иногда обратную связь вызвать архитектурно сложно
Пример: последние шаги большинства инсталляций или расчётов
Вот поэтому прогресс часто зависает на 100%. Система бывает просто не приспособлена, чтобы запускать эти последние шаги на другом процессоре. Удаление временных файлов, перерисовка пользовательского интерфейса, дополнительные мини-расчёты, которые выполняются с каждым кликом мышью…
Эти шаги можно загнать под прогресс, но это требует непропорционального объёма программистской работы.