Каким образом «современные ОО-языки в значительной степени исключили накладные расходы для внутрипроцессных вызовов»? - PullRequest
1 голос
/ 19 сентября 2009

Я читаю через сайт Source Making , в частности, раздел Рефакторинг . На странице, описывающей проблему Long Method , делается следующее утверждение:

Старые языки несут накладные расходы в вызовы подпрограмм, которые сдерживали люди из маленьких методов. Модерн ОО языки в значительной степени устранены это накладные расходы для внутрипроцессных вызовов.

Мне просто интересно, как современный ОО сделал это и как это сравнить со "старым" способом?

Ответы [ 7 ]

7 голосов
/ 19 сентября 2009

Не верь всему, что читаешь


Я думаю, что вы мудры к тому, чтобы осмотреть это утверждение. Это не имеет смысла.

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

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

Затраты на вызов метода в C намного меньше, чем в любом современном языке. В конце концов, современный язык имеет интерпретатор CLR, JVM или Ruby, который написан на C .

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

Действительно, они медленнее, а не быстрее, потому что именно так мы и хотим сейчас. В 3 раза больше накладных расходов, в 1000 раз больше скорости процессора, мы все равно выигрываем на 300 и имеем лучший язык.

2 голосов
/ 19 сентября 2009

Глядя на два предложения:

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

Вы задаетесь вопросом, что подразумевается под «старым» и «современным», и какие языковые функции могут влиять на производительность.

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

Так что, в основном, у «старых языков» меньше накладных расходов. Так что либо это мусор, либо они сравнивают «современные языки OO» с «Старые OO языки»

В традиционном языке OO, таком как Smalltalk (Smalltalk является самым старым «чистым» языком OO, но это также относится и к последним языкам, вдохновленным Smalltalk, таким как Ruby и Python; поскольку вызовы процедур идут, Ruby очень традиционен) каждый вызов процедуры потенциально является полиморфным методом, поэтому он ведет себя так, как будто его ищут по имени во время выполнения, когда выполняется вызов. Без изменений в языке современные реализации Smalltalk работают быстрее благодаря встроенным полиморфным методам, которые вызываются неоднократно.

Но Smalltalk не является современным языком (во многих отношениях это диалект Лиспа, поэтому его наследие - 1950-е годы, хотя он и появился только в 1970-х годах), и улучшена реализация, а не язык. Такое же улучшение существует во время выполнения Sun Java, времени выполнения Google JavaScript и многих распространенных средах выполнения lisp; и Java, и JavaScript являются более новыми ОО-языками, чем Smalltalk, но оптимизация вызова метода существует, несмотря на особенности этих языков (статическая типизация Java предполагает использование статической таблицы диспетчеризации, как во многих реализациях C ++, очень позднее связывание JavaScript и нехватка классов затрудняет реализацию оптимизации).

Я не могу придумать, как прочитать два предложения, и это правда.

Если вы посмотрите на более широкий контекст статьи, это означает, что стиль кода изменился с длинных методов на короткие.

Значит ли это, что этот код Smalltalk из 1970 теперь будет написан с использованием гораздо более коротких методов в более позднем ОО-языке, таком как Java или C ++ 0x?

enter [ self show. edit Menu show. scrollbar show ]

leave [ document hideselection. editMenu hide. scrollbar hide ]

outside
  [editMenu startup => []
  scrollbar startup => [self showdoc]
  ^false]

pendown [ document pendown ]

keyboard [ document keyboard ]

Это тоже не кажется вероятным. Изменение пришло с ОО, который так же современен, как Би Джис.

Однако произошел большой сдвиг в размере метода и рефакторинге в метод меньшего размера между процедурным и ОО-кодом.

Как только вы получили объект, поля которого содержат данные, которые вы используете, гораздо проще передать этот один объект в подпроцедуру, чем передавать дюжину различных локальных переменных, и это, вероятно, самая веская причина для небольших методов. чаще встречается в традиционных ОО, но это не сильно связано ни с производительностью, ни с современными языками. Просто очень много работы и очень много ошибок, чтобы спорить 12 аргументов типа double и int в и из функции в C.

Я был как в ситуации, когда смотрел длинный кусок процедурного кода, так и создавал объект (или структуру в C) для хранения состояния, позволяющего рефакторизовать его, и делал обратное (справляясь с большим количеством полей). в локальные переменные и вручную вставляя более короткие методы) для повышения производительности (в Java 1.3 IIRC). Поскольку вы можете сделать этот рефакторинг в ANSI C, он вряд ли ограничен современными языками OO.

2 голосов
/ 19 сентября 2009

Современные компиляторы фактически встроат метод для вас, если он короткий (а не виртуальный), что дает некоторое повышение производительности.

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

1 голос
/ 19 сентября 2009

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

0 голосов
/ 19 сентября 2009

Я думаю, что новые общие системы выигрывают от комбинации:

  1. Передача данных по ссылке в куче : эффективное устранение необходимости копирования больших объектов в стек.
  2. Сборка мусора : Сделать первый пункт полезным в реальной жизни, избавив программиста от кошмара управления жизненным циклом объекта. Например, возвращение объекта (фактически возвращая только ссылку на него) из вызова функции было бы кошмаром в системах без сбора мусора.
0 голосов
/ 19 сентября 2009

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

0 голосов
/ 19 сентября 2009

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

...