Почему Javascript ===/== Уравнение строки иногда имеет постоянную временную сложность и иногда имеет линейную временную сложность?

После того, как я обнаружил, что общие/последние реализации Javascript используют String Interning для повышения производительности (Используют ли общие реализации JavaScript для интернирования строк?), я думал, что === для строк получилось бы постоянное время O (1). Поэтому я дал неверный ответ на этот вопрос:

Сравнение производительности равенства строк в JavaScript

Так как согласно OP этого вопроса O (N), удвоение ввода строки удваивает время, необходимое для равенства. Он не предоставил jsPerf, поэтому требуется больше исследований,

Таким образом, мой сценарий с использованием интернирования строк будет выглядеть следующим образом:

var str1 = "stringwithmillionchars"; //stored in address 51242

var str2 = "stringwithmillionchars"; //stored in address 12313

"stringwithmillionchars" будет храниться один раз, если скажем в адресе 201012 памяти и оба str1 и str2 будут "указывать" на этот адрес 201012. Затем этот адрес можно определить с помощью какого-либо хэширования для сопоставления с определенными местоположениями в памяти.

Поэтому при выполнении

"stringwithmillionchars" === "stringwithmillionchars"

будет выглядеть как

getContentOfAddress(51242)===getContentOfAddress(12313)

или 201012 === 201012

который принимает O (1)/постоянное время

Обновления JSPerfs/Performance:

JSPerf, похоже, показывает постоянное время, даже если строка в 16 раз длиннее? Пожалуйста, посмотрите:

http://jsperf.com/eqaulity-is-constant-time

Вероятно, строки слишком малы по приведенному выше: Вероятно, это показывает линейное время (благодаря sergioFC) строки строятся с петлей. Я пробовал без функций - все еще линейное время/я немного изменил его http://jsfiddle.net/f8yf3c7d/3/.

В соответствии с https://www.dropbox.com/s/8ty3hev1b109qjj/compare.html?dl=0 (файл размером 12 МБ, созданный sergioFC), когда у вас есть строка, и вы уже присвоили значение в кавычках no важно, насколько велики t1 и t2 (например, 5930496 символов), он принимает 0-1ms/мгновенное время.

Похоже, что когда вы создаете строку, используя цикл for или функцию, строка не интернирована. Таким образом, интернирование происходит только тогда, когда вы напрямую назначаете строку с кавычками вроде var str = "test";

Ответы

Ответ 1

Основываясь на всех тестах производительности (см. исходное сообщение) для строк a и b, операция a === b принимает:

  • постоянное время O (1), если строки интернированы. Из примеров кажется, что интернирование только происходит с непосредственно назначенными строками типа var str = "test";, а не с его построением с конкатенацией с использованием for-loops или functions.

  • линейное время O (N), так как во всех остальных случаях сначала сравнивается длина двух строк. Если он равен, то мы имеем характер по сравнению с символом. Конечно, они не равны. N - длина строки.

Ответ 2

В соответствии с ECMAScript 5.1 Спецификация Строгое алгоритм равного сравнения, даже если тип сравниваемых объектов - String, все символы отмечены чтобы убедиться, что они равны.

  1. Если Type(x) является строкой, верните true , если x и y - это точно такая же последовательность символов (одинаковая длина и одинаковые символы в соответствующих позициях); return false.

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

Ответ 3

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

Затем, возьмите это как предоставленное. Здесь моя (недоказанная, неконтролируемая и, вероятно, не связанная с реальностью) теория.

Удовлетворение двух адресов памяти происходит быстро, независимо от того, сколько данных ссылается. Но сначала вы должны использовать эти строки. Если у вас есть код

var a = "1234";
var b = "1234";

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

  • Двигатель анализирует и ставит строки непосредственно при разборе кода. В этом случае равные строки должны иметь один и тот же адрес.
  • Двигатель может сказать: "Эти строки два больших, я не хочу их ставить" и имеет две копии.
  • В дальнейшем движок может продолжить эти строки.

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

Но, как я писал, дикая теория, для теории мудреца. Сначала я хотел бы увидеть JSPerf.