Слабый набор текста увеличивает или снижает производительность?

При написании интерпретируемых языков быстрее использовать слабую или строгую типизацию?

Мне было интересно это, потому что часто более быстрые интерпретируемые языки с динамической типизацией (Lua, Javascript) и фактически большинство интерпретируемых языков используют слабую типизацию.

Но, с другой стороны, строгая типизация дает гарантии, что слабая типизация - нет, поэтому возможны ли методы оптимизации с одним, которые невозможны с другим?


Под строго типизированным я подразумеваю отсутствие неявных преобразований между типами. Например, это было бы недопустимо для строго типизированного языка, но (возможно) допустимо для слабо типизированного языка: "5" * 2 == 10. Особенно печально известен Javascript для таких преобразований типов.


person orlp    schedule 10.03.2012    source источник
comment
+1 Интересный вопрос, но, боюсь, в целом на него сложно ответить. Я с нетерпением жду подробностей об оптимизации интерпретатора.   -  person    schedule 10.03.2012
comment
Чтобы прояснить, что вы подразумеваете под слабой и сильной типизацией? (Я стараюсь избегать использования этих терминов для причины, указанные здесь - люди используют их разными несовместимыми способами.)   -  person DSM    schedule 10.03.2012
comment
Строго типизированный, т. Е. Отсутствие неявных преобразований между типами. Например, это было бы недопустимо для строго типизированного языка, но (возможно) допустимо для слабо типизированного языка: "5" * 2 == 10. Javascript особенно известен такими преобразованиями типов. РЕДАКТИРОВАТЬ: добавил его к вопросу.   -  person orlp    schedule 10.03.2012
comment
Большинство современных движков JavaScript больше не интерпретируют, а компилируют прямо в байт-код в наши дни. Так что применить этот вопрос к этому языку сложно.   -  person Jivings    schedule 10.03.2012
comment
Jivings: почему машина, на которой она выполняется (непосредственно на машине или виртуальной машине), имеет значение для методов оптимизации?   -  person orlp    schedule 10.03.2012
comment
Я предполагаю, что JavaScript будет скомпилирован в соответствующий тип, чтобы он больше не был слабо типизирован.   -  person Jivings    schedule 10.03.2012
comment
Вы уверены, что это именно то, что вы подразумеваете под строго типизированным? вполне возможно, что неявное преобразование типов произойдет на языках, которые большинство людей сочтут строго типизированными - например, в java вы можете неявно преобразовать что угодно в строку, а в c вы можете преобразовать между числами с плавающей запятой и целыми числами. чаще, когда люди спрашивают о производительности, они обеспокоены тем, известен ли тип объекта во время компиляции, что может позволить компилятору оптимизировать (и это преимущество уменьшается благодаря своевременной компиляции, которая использует тип времени выполнения )   -  person andrew cooke    schedule 10.03.2012
comment
@andrewcooke: Я уверен, что это именно то, что я имею в виду под строго типизированным языком, ни Java, ни C не являются строго типизированными. Да, они статически типизированы, но не строго. (Например, в C вы можете неявно преобразовывать указатели на разные типы). Но на самом деле я имею в виду строго типизированный (без неявных преобразований), а не статически типизированный (объявление типа в коде).   -  person orlp    schedule 10.03.2012
comment
Ах хорошо. Извините за недопонимание.   -  person andrew cooke    schedule 10.03.2012
comment
@Jivings JS по-прежнему динамически типизирован, поэтому вы не можете согласиться на какой-либо тип во время компиляции (особенно при компиляции в байт-код - вы уверены, что вы не говорите о JIT-компиляторах?). Лучшее, что вы можете получить, - это предположить, что что-то обычно будет определенного типа, и сгенерировать код на основе этого предположения. Но вам по-прежнему нужны охранники (условные выражения, проверяющие, что предположение действительно верно) и более общая / менее оптимизированная версия, к которой можно вернуться (когда она была неправильной). Но все это не имеет значения для этого вопроса, так как это связано с динамической типизацией, а не со слабой / строгой типизацией.   -  person    schedule 10.03.2012
comment
Итак, какие интерпретируемые языки имеют строгую типизацию?   -  person andrew cooke    schedule 10.03.2012
comment
Этот вопрос не имеет смысла с двух точек зрения. Во-первых: накладные расходы на неявные преобразования возникают, когда эти неявные преобразования выполняются. Программа, не выполняющая таких неявных преобразований, будет такой же, независимо от того, поддерживает ли их язык. Итак, ваш вопрос похож на вопрос, работают ли языки программирования, имеющие встроенную функцию арктангенса, медленнее, чем языки, у которых их нет. Во-вторых: реализация неявных преобразований в языках с динамической типизацией сильно отличается от языков со статической типизацией; так что даже если в вашем вопросе был понятный   -  person ruakh    schedule 10.03.2012
comment
ответ на один случай, было бы бессмысленно пытаться применить этот ответ к другому случаю. (И, если на то пошло, это также иногда сильно отличается между разными языками, даже внутри этих групп.)   -  person ruakh    schedule 10.03.2012
comment
@andrewcooke: Какие из всех языков имеют строгую типизацию по этому определению? Навскидку, единственное, о чем я могу думать, - это функциональные языки, такие как Standard ML.   -  person ruakh    schedule 10.03.2012
comment
Например, Python очень близок к чистой строгой типизации с очень небольшим количеством операторов, определенных для работы со смешанными типами. Но Javascript, с другой стороны, имеет огромное количество преобразований, определенных между строками, числами и массивами, вводя множество моментов WTF. Поэтому я подумал, что, возможно, это дает преимущество в скорости.   -  person orlp    schedule 10.03.2012


Ответы (2)


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

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

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

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

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

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

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

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

[извините, если я все еще не понимаю. я беспокоюсь, что что-то упустил, потому что вопрос - и этот ответ - не кажутся интересными ...]

[edit: может быть, лучший способ задать одну и ту же (?) вещь - это что-то вроде "каковы сравнительные преимущества / недостатки различных способов, которыми динамические (позднее связывание?) языки обрабатывают преобразование типов?" потому что я думаю, что вы можете утверждать, что подход python является особенно мощным (выразительным), имея при этом те же затраты, что и другие интерпретируемые языки (и этот вопрос позволяет избежать споров о том, является ли python или любой другой язык «слабо типизированным» или нет). em>]

person andrew cooke    schedule 10.03.2012
comment
Как вы наверняка знаете, в Python очень мало неявных преобразований, если они вообще есть. Числовые типы продвигаются (в одностороннем порядке и всегда от одного типа к более общему), и можно утверждать, что _1 _ / _ 2 _ / _ 3 _ / _ 4_ неявно преобразовываются в логические значения (хотя можно также скажем, все объекты имеют значение истинности, и они просто получают это значение и обрабатывают его - тот факт, что _5 _ / _ 6_ возвращает один из операндов, поддерживает это представление). Помимо этого, я теперь знаю о любых неявных преобразованиях. И я сомневаюсь, что Python единственный в этом отношении. Так что я осмелюсь оспорить вашу причину №2. - person ; 10.03.2012
comment
под неявным преобразованием я подразумеваю неявный вызов таких методов, как __float__ - см. docs.python.org/ reference / datamodel.html # specialnames (так что __nonzero__ - это то, что вы имеете в виду при преобразовании в логическое значение). - person andrew cooke; 10.03.2012
comment
действительно распространенный пример в Python - преобразование в итератор. это повсюду в идиоматическом коде Python и реализовано таким же образом (__iter__ iirc). - person andrew cooke; 10.03.2012
comment
__float__ не вызывается неявно, он вызывается только из float AFAIK (возможно, и во время числового продвижения, но он у нас уже есть). __iter__ действительно вызывается неявно, но только в контексте for циклов и интерпретаций {list, dict, set}, поэтому он чрезвычайно ограничен и вызывается всегда. По этой причине я не считаю это неявным преобразованием. И большинство специальных методов вообще не конвертируются - они служат для таких целей, как доступ к атрибутам и перегрузка операторов. - person ; 10.03.2012
comment
__str__ - еще один распространенный. а iirc __float__ вызывается реализацией __add__ по умолчанию. в целом, я не уверен, о чем вы говорите - да, они размываются при отправке сообщений, и поэтому вы можете утверждать, что это не неявное преобразование типа, а вызов метода. и это круто - это именно то, что я имел в виду, когда сказал, что у Python есть хорошее решение и что спорить о том, что именно является слабой типизацией, а что нет, в значительной степени бессмысленно. так бессмысленно, что я больше не буду делать. - person andrew cooke; 10.03.2012
comment
Я не хочу сказать, что строго / слабая типизация - полезное различие или что мы должны обсудить, что именно считается слабой типизацией. Я просто сомневаюсь в вашей второй причине (что динамическая типизация требует неявных преобразований). В других ваших примерах: __str__ вызывается только str (это может быть косвенным, но определенно явным). Арифметические операторы, как мы оба уже заявили, действительно включают в себя некоторые неявные повышения / преобразования. - person ; 10.03.2012

Под строго типизированным я подразумеваю отсутствие неявных преобразований между типами.

"5" * 2 == 10

Проблема в том, что «слабая типизация» не является четко определенным термином, поскольку есть два очень разных способа, которыми могут происходить такие неявные преобразования, которые имеют почти противоположный эффект на производительность:

  • Способ языка сценариев: значения имеют тип среды выполнения, и язык неявно применяет семантические правила для преобразования между типами (например, форматирование двоичного числа как десятичной строки), когда операция вызывает другой тип. Это будет иметь тенденцию к снижению производительности, поскольку A) требует наличия информации о типе во время выполнения и b) требует, чтобы эта информация была проверена. Оба эти требования приводят к накладным расходам.
  • Способ C: во время выполнения это всего лишь байты. Если вы можете убедить компилятор применить операцию, которая принимает 4-байтовое целое число в строке, то в зависимости от того, как именно вы это делаете, первые 4 байта этой строки будут просто обрабатываться, как если бы они были (возможно, очень большими ) целое число, иначе произойдет переполнение буфера. Или демоны, вылетающие из носа. Этот метод не требует накладных расходов и приводит к очень высокой производительности (и очень впечатляющим сбоям).
person Michael Borgwardt    schedule 10.03.2012
comment
На самом деле существует три способа, поскольку вы упустили способ C: во время компиляции выражения имеют типы, а неявные преобразования могут быть вставлены для преобразования выражения из одного типа в другой по мере необходимости. Например, если i - это int, тогда 5.0 * i неявно преобразует i из int в double. Решение сделать это преобразование принимается во время компиляции. (То, что вы описываете как «способ C», на самом деле не является способом C для выполнения неявных преобразований; скорее, это результат обхода неявных преобразований C.) - person ruakh; 10.03.2012