Когда плохо – это достаточно хорошо?

Полезные статьи и переводы интересных статей
tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Когда плохо – это достаточно хорошо?

Сообщение tyomitch » 28.06.2005 (Вт) 10:10

Когда я прочитал статью на http://blogs.msdn.com/ericlippert/archi ... 53237.aspx , то она оказала на меня совершенно неизгладимое впечатление: такое я в последний раз получал от статьи МакКинни про VB.net (топиком ниже). Но статья Эрика Липперта во много раз короче, т.ч. мне легче, чем GSerg-у :-)
----------

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

Такие вопросы я получал десятки раз за последние семь лет. Вот этот, например, – в конце 1990-х:

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


Какой интересный вопрос о производительности VBScript! В таком языке как Си, объявление n байт локальных переменных компилируется всего лишь в команду изменения указателя стека на n байт. Уменьшение или увеличение n не оказывает никакого воздействия на время выполнения этой команды. Так же работает VBScript, или нет? Удивительно, но нет! Вот мои исследования:

Плохое исследование №1

Что ты объявил, то и получаешь. VBScript не может знать, не выполнишь ли ты впоследствии что-то вроде этого:

Код: Выделить всё
function foo()
  Dim bar
  Execute("bar = 123")


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


(Кстати, JScript.NET действительно пытается обнаружить такой код и оптимизировать его, но речь сейчас не об этом.)

Всё же, какие именно дополнительные расходы вызываются лишними объявлениями? Так случилось, что у меня в тот день под рукой оказалась машина, настроенная для измерения производительности, так что я смог ответить:

На моей машине каждая лишняя переменная (объявленная, но неиспользуемая) требует лишние 50 наносекунд при каждом вызове функции. Эта задержка, по-видимому, растёт линейно вместе с числом объявленных, но неиспользованных переменных; я не проверял случаи крайне большого числа лишних переменных, сочтя их нереалистичными. Также я не проверял случаи очень длинных имён переменных; хотя VBScript ограничивает имена переменных до 256 символов, задержка может увеличиваться при использовании более длинных имён.

Моя машина – Pentium III 927 МГц, так что эта задержка – где-то примерно 50 тактов процессора. На этой машине не установлен VTUNE, так что я не могу назвать точное число тактов.

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

Ещё, ты не указываешь, выполняется всё это на сервере или на клиенте. Это крайне важно при исследовании производительности!

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


А теперь я воспользуюсь возможностью и заявлю, что все описанные мной сейчас исследования почти совершенно бесполезны, потому что они скрывают гораздо б́ольшую проблему. В комнате есть слон, которого мы не замечаем. Сам факт, что пользователь спрашивает меня о производительности VBScript означает, что либо
а) этот пользователь – убеждённый фанат VBScript, которому просто интересно поговорить об особенностях языка;
или, что более вероятно,
б) у этого пользователя есть скрипт, который работает недостаточно быстро. Пользователю крайне важна производительность его скрипта.

Ого! Теперь понятно, почему наше исследование производительности оказывается бесполезным. Если пользователю так важна производительность, то почему же он выбрал динамический язык с поздним связыванием, со слабой типизацией, интерпретирующий неоптимизированный байт-код, – язык, специально созданный для быстроты разработки и жертвующий ради этого производительностью?

Плохое исследование №2

Если вам хочется, чтобы скрипт работал быстрее, то внимания требуют куда более важные вещи, чем 50-наносекундные задержки. Самое важное для эффективной оптимизации – найти самую неэффективную вещь и начать с неё. Например, единственный вызов, использующий необъявленную переменную, уже вносит в сотни раз б́ольшую задержку, чем от объявленной, но не использованной переменной. Единственный вызов объектной модели контейнера – в тысячи раз б́ольшую. Оптимизировать скрипт, сокращая 50-нс задержки, – это всё равно, что стричь газон, срезая самую короткую траву маникюрными ножничками и не обращая внимания на остальное. Это займёт много времени, а никаких изменений заметно так и не будет. Это иллюстрирует разницу между "активностью" и "продуктивностью". Не делайте так!

Но ещё лучшим советом было бы выбросить весь скрипт и переписать на Си всё с самого начала, раз производительность так важна.

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

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

Когда плохо – это достаточно хорошо?

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

Я читал статьи о скриптовых языках, которые утверждали вещи вроде "для проверки чётности числа нужно использовать And 1, а не Mod 2, потому что процессор быстрее выполняет команду And", как если бы VBScript компилировался в сильно оптимизированный машинный код. Люди, выбирающие используемые операторы на основе столь беспочвенных доводов, не напишут ясный читаемый код. Их программы будут сломанными, а "сломанная программа" – это наихудшая возможная оценка производительности, вне зависимости от скорости работы неверной программы.

Если вы хотите написать быстрый код – не важно, скриптовый или нет, – то не обращайте внимания на все эти статьи с "ценными советами", указывающие, какие операторы быстрее работают и сколько времени занимает объявление переменной. Чтобы написать быстрый код, не нужно набора дешёвых трюков – нужно исследование пользовательских запросов, задающее цели, и затем ведение тщательно спланированных измерений и коррекций, пока заданные цели не будут достигнуты.

1) План должен основываться на пользовательских запросах. Необходимо знать, каких именно целей добивается улучшение производительности.
2) Необходимо знать, что именно измерять для проверки достижения этих целей. Что именно критично – пропускная способность? время до начала вывода? до конца вывода? масштабируемость?
3) Нужно измерять систему целиком, а не только отдельные её части.
4) Измерения должны быть тщательными и постоянными.

Именно так делает команда MSN, и они умеют делать масштабируемые веб-сайты.

Я знаю, что люди хотят слышать не это. Люди относят к анализу производительности те вещи, которые, кажется, потеряли актуальность вместе с PDP-11. Скрипты, выполняемые на веб-серверах, невозможно оптимизировать, оттачивая отдельные строки кода – это не Си, где можно вычислить точные временные затраты на каждый оператор. В скрипте нужно смотреть на всю программу целиком и атаковать самые затратные вещи – иначе окажется, что огромный объём работы сделан ради нулевого выигрыша.

Но сначала нужно узнать, какие именно цели преследуются. Выясните, что важно вашим пользователям. Пользовательские приложения должны быть отзывчивыми – обработка данных может занять пять минут или час, но нажатие кнопки должно быть обработано за 0,2 секунды – иначе приложение будет казаться зависшим. Масштабируемые веб-приложения должны быть ослепительно быстрыми – разница между 25 мс и 50 мс даёт 20 страниц в секунду. Но какая у пользователя пропускная способность? Если 10Кб-страница сгенерируется на 25 мс быстрее, парень с модемом на 14000 б/с не заметит никакой разницы.

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

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

И ещё не забывайте, что ПРАВИЛЬНО лучше, чем БЫСТРО. Пишите код как можно проще: осмысленный код можно исследовать и поддерживать, и именно поэтому он производительнее. Рассмотрим наш пример с неиспользуемым объявлением: тот факт, что оно вносит 50 нс задержки, не имеет значения. Это неиспользуемая переменная; это бессмысленный код; это ненужная помеха для программистов, поддерживающих скрипт. Именно это – его настоящее влияние на производительность скрипта: оно мешает программистам, анализирующим производительность кода, оптимизировать скрипт!
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 28.06.2005 (Вт) 12:03

Круто :)

А почему ударения на буквах стоят на одну букву раньше?
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Сообщение Ruslan Demidow » 28.06.2005 (Вт) 17:08

Тёмыч.
Как зядлый любитель скриптов выскажу своё мнение по поводу статьи и по поводу скриптов (конкретно VBS).
По статье: Вроде бы и гладко написано, но не скажу, что статья на меня произвела сильное впечатление. Имхо, автор америку не открыл, указав, что vb-скрипты медленная вещь. Конечно, для меня новО, что лишние переменные замедляют работу интерпретатора скриптов.
Ведь скрипт - это же всего лишь указания интерпретатору. Он ведь даже не компилируется, а обрабатывается построчно (о чём можно утверждать исходя из того, что если создать в разных местах скрипта две или три ошибки специально, то при каждом запуске и исправлении очередной ошибки, интерпретатор будет ругаться на следующую, а не на все сразу. :))
И было новО (но вполне можно было догадаться), что любой вызов внешнего объекта вызывает ещё большие задержки. Читать было интересно. Но в тоже время для себя нового и полезного я почерпнул, только то, что было описано выше. Остальное вода, имхо.
По скриптам: Да vb-скрипт - медленная вещь, но зато универсальная. Не надо ни IDE (нужен лишь блокнот), не надо компилятора (кроме как самой системы :) ). Это быстрое и удобное подручное средство в области автоматизации обычных, "рутинных" задач. Не больше. Но честное слово - лично для меня писать на VBS - удовольствие ни в коей мере не меньшее (а может быть и даже большее), чем на VB.
А некоторые вещи (по затратам) проще, дешевле и быстрее написать на VBS, чем на каком либо другом языке более высокого уровня.
Вот например получение данных о сетевом окружении и его настройках. Для меня лично, если писать программу - это займёт не меньше недели (а то и больше).
На VBS же я написал этот скрипт за 3 часа (два из них ушли на закачку из инета информации по WMI, описания объектов, а так же на первые несколько неудачных опытов с SQL-запросами - ну не знаю я SQL. По наитию делал.) Скрипт сделал. Работает. Легко настраиваем (скрипт) и расширяем. Чего ещё надо? Добавить вывод новой информации? Да легко - только знай добавляй в текстовую строку вывод значений дополнительных свойств объекта. :)

НО... Мой странный и кривой опус в сторону VBS ни в коей мере не умаляет ни труд автора статьи, ни твой труд Артём. Какое бы ни было моё отношение к данной статье: РЕСПЕКТ ТЕБЕ!! :)
Если есть желание, то мне было бы интересно представить свой скритп здесь, и исходя из изложенного в данной статье получить ваши (я имею в виду гуру данного форума) мнения по поводу ускорения и "улучшения" данного скрипта в свете прочитанных здесь мною постулатов по поводу VBS.

Уф.... Что-то понесло меня... :)
Это Ж-ж-ж-ж неспроста (с) Винни-Пух

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 28.06.2005 (Вт) 18:32

GSerg писал(а):А почему ударения на буквах стоят на одну букву раньше?

Писал в WinXP, там почему-то они рисуются над следующей буквой, а не над предыдущей.
Почему латинские буквы с ударениями в Юникоде есть, а русских нету?

Если есть способ расставить ударения над русскими буквами так, чтобы они во всех Виндах оказывались на своём месте - с интересом выслушаю.


2Ruslan:
Смысл статьи не в том, что скрипты - медленная вещь; смысл статьи в том, что многие люди не понимают, что такое скрипты. И что правильный скрипт в нужном месте - достаточно быстрая вещь. Нужно только перед тем, как начать писать код, понять, что такое - достаточно быстрая вещь.
Поэтому мне статья и показалась такой интересной, что она не только о VBScript, она о программировании вообще: что скорость программы определяется её общим планом, а не деталями реализации.

Скрипт компилируется в байт-код, а не интерпретируется построчно. Интерпретатор ругается только на одну ошибку, потому что он так написан. VB6 при компиляции тоже ругается только на одну ошибку, а не на все сразу - может, и VB6-код выполняется построчно?

Ruslan Demidow писал(а):vb-скрипт - медленная вещь, но зато универсальная. ... Это быстрое и удобное подручное средство ... Не больше.

Раз "не больше", значит уже не универсальное, так? ;-)
Мне кажется, ты имел в виду "гибкая" вместо "универсальная".
Потому что скрипты - вовсе не универсальная вещь, и об этом тоже явно написано в статье :-)


Для иллюстрации приведу один из комментариев к переведённой статье:
Bob Riemersma писал(а):Я считаю, что всюду, где это возможно, скрипт нужно использовать именно в его (первоначальном?) назначении "клея". Недавно я видел, как кто-то просил: "Вот у меня есть два CSV-файла, и я хочу объединить их в один – помогите с кодом". Один из ответов включал в себя ввод-вывод через FSO, кучу Split()-ов, объект Dictionary, Join()-ы, то, сё. По существу, парню был нужен простой INNER JOIN, и я предложил ему задействовать ADO, Jet и текстовый драйвер – используя как раз INNER JOIN.

Более короткий скрипт, и работал офигенно быстрее. Погляди-ка.

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

Ruslan Demidow
Мужчина!
Мужчина!
Аватара пользователя
 
Сообщения: 987
Зарегистрирован: 25.03.2004 (Чт) 13:39
Откуда: N.Novgorod

Сообщение Ruslan Demidow » 28.06.2005 (Вт) 23:00

tyomitch писал(а):2Ruslan:
Смысл статьи не в том, что скрипты - медленная вещь; смысл статьи в том, что многие люди не понимают, что такое скрипты. И что правильный скрипт в нужном месте - достаточно быстрая вещь.

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

tyomitch писал(а):Нужно только перед тем, как начать писать код, понять, что такое - достаточно быстрая вещь.
Поэтому мне статья и показалась такой интересной, что она не только о VBScript, она о программировании вообще: что скорость программы определяется её общим планом, а не деталями реализации.

Здесь я с тобой согласен на все 100%. :)

tyomitch писал(а):Скрипт компилируется в байт-код, а не интерпретируется построчно. Интерпретатор ругается только на одну ошибку, потому что он так написан. VB6 при компиляции тоже ругается только на одну ошибку, а не на все сразу - может, и VB6-код выполняется построчно?

Ну нет конечно (это про VB6). :)
А про компиляцию тогда вопрос: VB6 компилирует в файл на диске (екзешник). VBS - в память что ли? Если так. То в любом случае если в в скрипте ошибка (в синтаксисе), то почему VBS пока не дойдёт до неё - ни словом не обмолвится про неё ещё при запуске? У меня напрашивается только один вывод - что компиляция и выполнение происходит на лету (как бы построчно). Т.е. скрипт не спотыкается на этапе своей "компиляции", а спотыкается только при попытке выполнить строку.

tyomitch писал(а):
Ruslan Demidow писал(а):vb-скрипт - медленная вещь, но зато универсальная. ... Это быстрое и удобное подручное средство ... Не больше.

Раз "не больше", значит уже не универсальное, так? ;-)

Ну не знаю. Я имел ввиду универсальное - в смысле применения - на всём и везде (по крайней мере в продуктах от MS). Хотя ты конечно же прав в своём выводе.

tyomitch писал(а):Мне кажется, ты имел в виду "гибкая" вместо "универсальная".
Потому что скрипты - вовсе не универсальная вещь, и об этом тоже явно написано в статье :-)

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

tyomitch писал(а):Для иллюстрации приведу один из комментариев к переведённой статье:
Bob Riemersma писал(а):Я считаю, что всюду, где это возможно, скрипт нужно использовать именно в его (первоначальном?) назначении "клея". Недавно я видел, как кто-то просил: "Вот у меня есть два CSV-файла, и я хочу объединить их в один – помогите с кодом". Один из ответов включал в себя ввод-вывод через FSO, кучу Split()-ов, объект Dictionary, Join()-ы, то, сё. По существу, парню был нужен простой INNER JOIN, и я предложил ему задействовать ADO, Jet и текстовый драйвер – используя как раз INNER JOIN.

Более короткий скрипт, и работал офигенно быстрее. Погляди-ка.

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

Ну что ж. Есть и такие примеры. И они к сожалению встречаются чаще чем хотелось бы. Стрельба из пушки по воробьям.
Яркий пример тому - всякие мелочи типа автоархивации средствами nnCron'а или переименование определённых файлов в некоторых каталогах. Бывает, что человек спросит: а мне бы сделать то что делает стандартный планировщик, только вот немножко бы интелектуальности добавить. Ему говорят - ставь nnCron. А про то, что нужно изучать, я бы сказал, не очень синтаксически понятный язык Форт для использования хотя бы на 30-40% возможностей Крона - не говорят.
Скрипты же - они почти на каждом шагу. При том даже в папке виндов несколько валяются уже сразу после установки. Только изучить немножко. Приложить голову. И... Ну да ладно. Хотя тоже конечно придётся немножко поучить скриптовый язык. :)
Это Ж-ж-ж-ж неспроста (с) Винни-Пух

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 29.06.2005 (Ср) 4:14

tyomitch писал(а):Если есть способ расставить ударения над русскими буквами так, чтобы они во всех Виндах оказывались на своём месте - с интересом выслушаю.

Я обычно пользуюсь тем, что буквы о и а что русские, что латинские - а ставить ударение на другие как-то не приходилось :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас


Вернуться в VBStreets Knowledge Base

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9

    TopList