Программирование на языке Ruby - [195]
>anagrams.each
) выполняются очень быстро.Мы также видим, что >Hash#[]
— дорогая операция (главным образом потому что часто выполняется); на 1.4 миллиона вызовов было потрачено почти 11 секунд.
Обратите внимание, что метод >readlines
оказался чуть ли не в самом конце списка. Эта программа тратит время не на ввод/вывод, а на вычисления. На чтение всего файла ушло всего-то четверть секунды.
Но этот пример не показывает, в чем истинная ценность профилирования. В программе нет ни методов, ни классов. На практике вы, скорее всего, увидите свои методы среди системных. И тогда будете точно знать, какие из ваших методов находятся в числе первых 20 «пожирателей времени».
Надо ясно понимать, что профилировщик Ruby (видно, по иронии судьбы) работает медленно. Он подключается к программе во многих местах и следит за ее выполнением на низком уровне (причем сам написан на чистом Ruby). Так что не удивляйтесь, если ваша программа в ходе сеанса профилирования будет работать на несколько порядков медленнее. В нашем примере она работала 7 минут 40 секунд (460 секунд), то есть в 25 раз медленнее обычного.
Помимо профилировщика, есть еще один низкоуровневый инструмент — стандартная библиотека >benchmark
, которая тоже полезна для измерения производительности.
Один из способов ее применения — вызвать метод >Benchmark.measure
и передать ему блок.
>require 'benchmark'
>file = "/usr/share/dict/words"
>result = Benchmark.measure { File.readlines(file) }
>puts result
># Выводится: 0.350000 0.070000 0.420000 ( 0.418825)
Этот метод выводит следующую информацию:
• время, затраченное процессором в режиме пользователя (в секундах);
• время, затраченное процессором в режиме ядра (в секундах);
• полное затраченное время — сумму вышеупомянутых величин;
• время работы программы (по часам).
Для сравнения производительности отдельных участков удобен метод >Benchmark.bm
. Передайте ему блок, а он сам передаст блоку объект формирования отчета. Если вызвать этот объект, передав ему метку и блок, то он выведет метку, а за ней временные характеристики блока. Пример:
>require 'benchmark'
>n = 200_000
>s1 = ""
>s2 = ""
>s3 = ""
>Benchmark.bm do |rep|
> rep.report("str << ") { n.times { s1 << "x" } }
> rep.report("str.insert ") { n.times { s3.insert(-1,"x") } }
> rep.report("str += ") { n.times { s2 += "x" } }
>end
Здесь мы сравниваем три способа добавить символ в конец строки, дающие один и тот же результат. Чтобы можно было получить более точные цифры, каждая операция выполняется 200000 раз. Вот что вышло:
> user system total real
>str << 0.180000 0.000000 0.180000 ( 0.174697)
>str.insert 0.200000 0.000000 0.200000 ( 0.200479)
>str += 15.250000 13.120000 28.370000 (28.375998)
Обратите внимание, что последний вариант на два порядка медленнее остальных. Почему? Какой урок можно извлечь отсюда?
Вы можете предположить, что оператор >+
почему-то работает медленно, но дело в другом. Это единственный из трех способов, который не работает с одним и тем же объектом, а каждый раз создает новый.
Стало быть, вывод такой: создание объекта — дорогая операция. Библиотека Benchmark может преподать много подобных уроков, но я все же рекомендую сначала заняться высокоуровневым профилированием.
16.7. Объекты печати
Метод >inspect
(и вызывающий его метод >p
) предназначен для вывода объектов в виде, понятном человеку. В этом смысле он является связующим звеном между тестированием и отладкой, поэтому рассмотрение его в этой главе оправданно.
Проблема в том, что результат, формируемый методом >p
, бывает трудно читать. Из-за этого и появилась библиотека >pp
, добавляющая одноименный метод. Рассмотрим следующий искусственный пример объекта >my_obj
:
>class MyClass
> attr_accessor :alpha, :beta, :gamma
> def initialize(a,b,c)
> @alpha, @beta, @gamma = a, b, с
> end
>end
>x = MyClass.new(2, 3, 4)
>y = MyClass.new(5, 6, 7)
>z = MyClass.new(7, 8, 9)
>my_obj = { x => y, z => [:p, :q] }
>p my_obj
Вызов метода >p
печатает следующее:
>{#
> @gamma=4>=>#
> #
Все правильно и в общем-то даже читаемо. Но… некрасиво. А давайте затребуем библиотеку >pp
и воспользуемся предоставляемым ей методом >pp
:
>require 'pp'
># ...
>pp my_obj
Теперь вывод приобретает такой вид:
>{#
> #
> #
Мы получили хотя бы пробелы и разбиение на строки. Уже лучше. Но можно пойти еще дальше. Предположим, что в классе >MyClass
определен специальный метод >pretty_print
:
>class MyClass
> def pretty_print(printer)
> printer.text "MyClass(#@alpha, #@beta, #@gamma)"
> end
>end
Аргумент printer передается вызывающей программой (или методом pp). Это аккумулятор текста, являющийся экземпляром класса >PP
; мы вызываем его метод >text
и передаем ему текстовое представление >self
. Вот что получается в результате:
>{MyClass(7, 8, 9)=>[:p, :q] , MyClass(2, 3, 4)=>MyClass(5, 6, 7)}
Разумеется, можно настроить поведение по своему вкусу. Можно, например, печатать переменные экземпляра на разных строчках с отступами.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Сейчас во многих школах, институтах и других учебных заведениях можно встретить компьютеры старого парка, уже отслужившие свое как морально, так и физически. На таких компьютерах можно изучать разве что Dos, что далеко от реалий сегодняшнего дня. К тому же у большинства, как правило, жесткий диск уже в нерабочем состоянии. Но и выбросить жалко, а новых никто не дает. Различные спонсоры, меценаты, бывает, подарят компьютер (один) и радуются, как дети. Спасибо, конечно, большое, но проблемы, как вы понимаете, этот компьютер в общем не решает, даже наоборот, усугубляет, работать на старых уже как-то не хочется, теперь просто есть с чем сравнивать.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.