Jump to content

Thunk

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

Этот термин возник как причудливая неправильная форма глагола думать . Это относится к первоначальному использованию преобразователей в компиляторах ALGOL 60 , что требовало специального анализа (мысли), чтобы определить, какой тип процедуры генерировать. [1] [2]

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

Простая реализация «вызова по имени» может заменить код выражения аргумента при каждом появлении соответствующего параметра в подпрограмме, но это может привести к созданию нескольких версий подпрограммы и нескольких копий кода выражения. В качестве улучшения компилятор может создать вспомогательную функцию, называемую thunk , которая вычисляет значение аргумента. Адрес и окружение [а] этой вспомогательной подпрограммы затем передаются исходной подпрограмме вместо исходного аргумента, где ее можно вызывать столько раз, сколько необходимо. Питер Ингерман впервые описал переходники применительно к языку программирования ALGOL 60, который поддерживает оценку по имени. [4]

Приложения

[ редактировать ]

Функциональное программирование

[ редактировать ]

Хотя индустрия программного обеспечения в значительной степени стандартизировала оценку вызовов по значению и вызовов по ссылке , [5] продолжалось активное изучение обращения по имени В сообществе функционального программирования . В результате этого исследования была создана серия языков программирования с ленивым вычислением , в которых некоторый вариант вызова по имени является стандартной стратегией оценки. Компиляторы для этих языков, такие как компилятор Glasgow Haskell , в значительной степени полагаются на преобразователи с дополнительной функцией, заключающейся в том, что преобразователи сохраняют свой первоначальный результат, чтобы можно было избежать его повторного расчета; [6] это известно как мемоизация или вызов по необходимости .

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

Ниже приведена простая демонстрация на JavaScript (ES6):

// 'hypot' is a binary function
const hypot = (x, y) => Math.sqrt(x * x + y * y);

// 'thunk' is a function that takes no arguments and, when invoked, performs a potentially expensive
// operation (computing a square root, in this example) and/or causes some side-effect to occur
const thunk = () => hypot(3, 4);

// the thunk can then be passed around without being evaluated...
doSomethingWithThunk(thunk);

// ...or evaluated
thunk(); // === 5

Объектно-ориентированное программирование

[ редактировать ]

Thunk полезны в объектно-ориентированного программирования платформах , которые позволяют классу наследовать несколько интерфейсов , что приводит к ситуациям, когда один и тот же метод может быть вызван через любой из нескольких интерфейсов. Следующий код иллюстрирует такую ​​ситуацию в C++ .

class A {
 public:
  virtual int Access() const { return value_; }

 private:
  int value_;
};

class B {
 public:
  virtual int Access() const { return value_; }

 private:
  int value_;
};

class C : public A, public B {
 public:
  int Access() const override { return better_value_; }

 private:
  int better_value_;
};

int use(B *b) { return b->Access(); }

int main() {
  // ...
  B some_b;
  use(&some_b);
  C some_c;
  use(&some_c);
}

В этом примере код, сгенерированный для каждого из классов A, B и C, будет включать таблицу диспетчеризации , которую можно использовать для вызова Access на объекте этого типа через ссылку того же типа. Класс C будет иметь дополнительную таблицу диспетчеризации, используемую для вызова Access на объект типа C через ссылку типа B. Выражение b->Access() будет использовать собственную таблицу диспетчеризации B или дополнительную таблицу C, в зависимости от типа объекта, на который ссылается b. Если он ссылается на объект типа C, компилятор должен гарантировать, что C Access реализация получает адрес экземпляра для всего объекта C, а не унаследованной части B этого объекта. [8]

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

Только что описанное решение имеет проблемы, аналогичные описанной ранее наивной реализации вызова по имени: компилятор генерирует несколько копий кода для вычисления аргумента (адреса экземпляра), а также увеличивает размеры таблицы диспетчеризации для хранения смещений. В качестве альтернативы компилятор может сгенерировать корректирующий преобразователь вместе с реализацией C Access который корректирует адрес экземпляра на необходимую величину, а затем вызывает метод. Thunk может появиться в таблице диспетчеризации C для B, тем самым устраняя необходимость для вызывающих абонентов самостоятельно корректировать адрес. [9]

Численные расчеты, требующие оценок в нескольких точках

[ редактировать ]

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

Совместимость

[ редактировать ]

Thunks широко используются для обеспечения взаимодействия между программными модулями, подпрограммы которых не могут напрямую вызывать друг друга. Это может произойти из-за того, что подпрограммы имеют разные соглашения о вызовах , выполняются в разных режимах ЦП или адресных пространствах или по крайней мере одна из них запускается на виртуальной машине . Компилятор (или другой инструмент) может решить эту проблему, создав преобразователь, который автоматизирует дополнительные шаги, необходимые для вызова целевой процедуры, будь то преобразование аргументов, копирование их в другое место или переключение режима ЦП. Успешный переход сводит к минимуму дополнительную работу, которую должен выполнить вызывающий абонент по сравнению с обычным вызовом.

Большая часть литературы по вопросам совместимости относится к различным платформам Wintel , включая MS-DOS , OS/2 , [10] Окна [11] [12] [13] [14] и .NET , а также к переходу с 16-битной на 32-битную адресацию памяти. Поскольку клиенты перешли с одной платформы на другую, возникла необходимость поддержки устаревшего программного обеспечения, написанного для старых платформ.

Переход от 32-битного к 64-битному коду на x86 также использует форму преобразования ( WoW64 ). Однако, поскольку адресное пространство x86-64 больше, чем пространство, доступное для 32-битного кода, старый механизм «общего преобразователя» нельзя было использовать для вызова 64-битного кода из 32-битного кода. [15] Единственный случай, когда 32-битный код вызывает 64-битный код, — это преобразование API Windows в WoW64 в 32-битный формат.

Наложения и динамическое связывание

[ редактировать ]

В системах, в которых отсутствует аппаратное обеспечение автоматической виртуальной памяти , thunks может реализовать ограниченную форму виртуальной памяти, известную как оверлеи . С помощью наложений разработчик делит код программы на сегменты, которые можно загружать и выгружать независимо, и определяет точки входа в каждый сегмент. Сегмент, который вызывает другой сегмент, должен делать это косвенно через таблицу ветвей . Когда сегмент находится в памяти, записи его таблицы ветвей переходят в сегмент. Когда сегмент выгружается, его записи заменяются «перезагрузочными санками», которые могут перезагрузить его по требованию. [16]

Аналогично, системы, которые динамически связывают модули программы во время выполнения, могут использовать переходники для соединения модулей. Каждый модуль может вызывать другие через таблицу переходов, которую компоновщик заполняет при загрузке модуля. Таким образом, модули могут взаимодействовать без предварительного знания того, где они расположены в памяти. [17]

См. также

[ редактировать ]

Thunk технологии

[ редактировать ]
[ редактировать ]

Примечания

[ редактировать ]
  1. ^ Thunk — это ранний ограниченный тип закрытия . Среда, передаваемая для преобразователя, — это среда выражения, а не среда вызываемой процедуры. [3]
  1. ^ Эрик Рэймонд отвергает «пару звукоподражательных мифов, циркулирующих о происхождении этого термина», и цитирует изобретателей «thunk», напоминая, что этот термин «был придуман после того, как они поняли (в первые часы после нескольких часов обсуждения), что тип аргумента в Алголе-60 можно было рассчитать заранее, немного подумав во время компиляции [...] Другими словами, об этом «уже думали», поэтому его окрестили thunk , что означает «прошедшее время»; думать» в два часа ночи». См.: Раймонд, Эрик С. (1996). Раймонд, Эрик С. (ред.). Новый словарь хакера . МТИ Пресс. п. 445. ИСБН  9780262680929 . Проверено 25 мая 2015 г.
  2. ^ См. Ингерман (1961): «Переводчик знает, какой тип структуры создать, учитывая формирование фактического параметра и ранее отсканированные объявления.… [Когда] когда объявление процедуры компилируется, переводчик, опять же, наблюдая за синтаксисом , знает, какой адрес ожидать от преобразователя."
  3. ^ Э. Т. Айронс (1 января 1961 г.). «Комментарии к реализации рекурсивных процедур и блоков в АЛГОЛе» . Коммуникации АКМ . 4 (1). Ассоциация вычислительной техники (ACM): 65–69. дои : 10.1145/366062.366084 . ISSN   0001-0782 . S2CID   14646332 .
  4. ^ Ингерман, П.З. (1 января 1961 г.). «Thunks: способ компиляции операторов процедур с некоторыми комментариями к объявлениям процедур» . Коммуникации АКМ . 4 (1). Ассоциация вычислительной техники (ACM): 55–58. дои : 10.1145/366062.366084 . ISSN   0001-0782 . S2CID   14646332 .
  5. ^ Скотт, Майкл (2009). Прагматика языков программирования . п. 395.
  6. ^ Марлоу, Саймон (2013). Параллельное и параллельное программирование на Haskell . п. 10.
  7. ^ Кейннек, Кристиан (2003). Лисп в маленьких кусочках . п. 176.
  8. ^ Страуструп, Бьярне (осень 1989 г.). «Множественное наследование для C++» (PDF) . Вычислительные системы . 1 (4). УСЕНИКС . Проверено 4 августа 2014 г.
  9. ^ Дрисен, Карел; Хёльцле, Урс (1996). «Прямая стоимость вызовов виртуальных функций в C++» (PDF) . Материалы конференции ACM SIGPLAN 1996 г. по системам, языкам и приложениям объектно-ориентированного программирования, OOPSLA 1996, Сан-Хосе, Калифорния, США, 6-10 октября 1996 г. 11-я OOPSLA 1996: Сан-Хосе, Калифорния, США. АКМ . ISBN  0-89791-788-Х . Архивировано из оригинала (PDF) 29 декабря 2019 г. Проверено 24 февраля 2011 г. [ мертвая ссылка ]
  10. ^ Калькот, Джон (май 1995 г.). «Thunking: использование 16-битных библиотек в OS/2 2.0» . Журнал разработчиков OS/2 . 7 (3): 48–56.
  11. ^ Кинг, Адриан (1994). Внутри Microsoft Windows 95 (2-е изд.). Редмонд, Вашингтон, США: Microsoft Press . ISBN  1-55615-626-Х .
  12. ^ Руководство программиста по Microsoft Windows 95: ключевые темы по программированию для Windows от группы разработчиков Microsoft Windows (1-е изд.). Редмонд, Вашингтон, США: Microsoft Press . 1 июля 1995 г. ISBN  1-55615-834-3 . Проверено 26 мая 2016 г. {{cite book}}: |work= игнорируется ( помогите )
  13. ^ Хазза, Карен (1997). Написание Windows VxD и драйверов устройств — секреты программирования драйверов виртуальных устройств (2-е издание, 2-е изд.). Лоуренс, Канзас, США: Книги по исследованиям и разработкам / Miller Freeman, Inc. ISBN  0-87930-438-3 .
  14. ^ Каулер, Барри (август 1997 г.). Язык ассемблера Windows и системное программирование - 16- и 32-битное низкоуровневое программирование для ПК и Windows (2-е изд.). Лоуренс, Канзас, США: Книги по исследованиям и разработкам / Miller Freeman, Inc. ISBN  0-87930-474-Х .
  15. ^ «Почему вы не можете выбрать между 32-битной и 64-битной Windows?» . Старая новая вещь . 20 октября 2008 г.
  16. ^ Брайт, Уолтер (1 июля 1990 г.). «Виртуальная память для 640К DOS» . Журнал доктора Добба . Проверено 6 марта 2014 г.
  17. ^ Левин, Джон Р. (2000) [октябрь 1999 г.]. Линкеры и загрузчики . Серия Моргана Кауфмана по разработке программного обеспечения и программированию (1-е изд.). Сан-Франциско, США: Морган Кауфманн . ISBN  1-55860-496-0 . OCLC   42413382 . Архивировано из оригинала 5 декабря 2012 г. Проверено 12 января 2020 г. Код: [1] [2] Ошибки: [3]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: a2a08d52387d97b571f6502d24da46f8__1719038040
URL1:https://arc.ask3.ru/arc/aa/a2/f8/a2a08d52387d97b571f6502d24da46f8.html
Заголовок, (Title) документа по адресу, URL1:
Thunk - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)