Ще з мого першого класу програмування в середній школі я чув, що струнні операції проходять повільніше - тобто дорожче - ніж міфічна "середня операція". Чому вони роблять їх так повільно? (Це питання лишилося навмисно широким.)
Ще з мого першого класу програмування в середній школі я чув, що струнні операції проходять повільніше - тобто дорожче - ніж міфічна "середня операція". Чому вони роблять їх так повільно? (Це питання лишилося навмисно широким.)
Відповіді:
"Середня операція" відбувається на примітивах. Але навіть у мовах, де рядки розглядаються як примітиви, вони все ще є масивами під кришкою, і все, що стосується всієї струни, займає час O (N), де N - довжина рядка.
Наприклад, додавання двох чисел зазвичай займає 2-4 інструкції ASM. Об'єднання ("додавання") двох рядків вимагає нового розподілу пам'яті та однієї або двох струнних копій, включаючи всю нитку.
Певні мовні фактори можуть погіршити ситуацію. Наприклад, у C, рядок - це просто вказівник на масив символів, що закінчується нулем. Це означає, що ви не знаєте, скільки триває, тому немає можливості оптимізувати цикл копіювання рядків за допомогою операцій швидкого переміщення; Вам потрібно скопіювати один символ одночасно, щоб ви могли протестувати кожен байт для нульового термінатора.
char*
, що не strbuf
, а ви повернетесь до площі 1. Є тільки стільки ви може зробити, коли погана конструкція випечена на мові.
buf
вказівник є. Я ніколи не мав на увазі, що це недоступно; скоріше, що це потрібно. Будь-який код, який не знає про ваш оптимізований, але нестандартний тип рядка, включаючи речі, настільки фундаментальні, як стандартна бібліотека , все ще повинен відкидатися на повільному, небезпечному char*
. Ви можете викликати цей FUD, якщо хочете, але це не робить його неправдою.
Це стара нитка, і я думаю, що інші відповіді чудові, але щось не помічаю, тож ось мої (пізні) 2 копійки.
Проблема з рядками полягає в тому, що вони є громадянами другого класу на більшості мов, і насправді більшість часу насправді не є частиною самої мовної специфікації: це бібліотечна конструкція, що має синтаксичне цукрове покриття на вершині щоб зробити їм менше болю.
Прямий наслідок цього полягає в тому, що мова приховує дуже велику частину їх складності подалі від зору, і ви платите за підлі побічні ефекти, тому що у вас з'являється звичка розглядати їх як атомну сутність низького рівня, як інші примітивні типи (як пояснено у відповіді на першокласність та ін.).
Одним із елементів цієї основної "складності" є те, що більшість рядкових реалізацій вдасться використати просту структуру даних з деяким суміжним простором пам'яті для представлення рядка: ваш добрий масив.
Це має сенс, майте на увазі, оскільки ви хочете, щоб доступ до рядка в цілому був швидким. Але це означає потенційно жахливі витрати, коли ви хочете маніпулювати цим рядком. Доступ до елемента в середині може бути швидким, якщо ви знаєте, за яким індексом ви шукаєте , але шукати елемент на основі умови - це не так.
Навіть повернення розміру рядка може бути дорогим, якщо ваша мова не кешує довжину рядка і потрібно пройти через нього, щоб підрахувати символи.
З подібних причин додавання елементів до рядка виявиться дорогим, оскільки вам, швидше за все, потрібно буде виділити деяку кількість пам'яті для здійснення цієї операції.
Отже, різні мови застосовують різні підходи до цих питань. Наприклад, Java взяла на себе сміливість зробити свої рядки незмінними з якихось поважних причин (довжина кешування, безпека потоку), а для своїх змінних аналогів (StringBuffer і StringBuilder) вирішить виділити розмір за допомогою великих розмірів, щоб не потрібно виділяти їх щоразу, але швидше сподіваюсь на найкращі сценарії. Як правило, це працює добре, але низька сторона полягає в тому, щоб іноді оплачувати вплив пам’яті.
Крім того, і знову це пов'язано з тим, що синтаксичне цукрове покриття вашої мови приховує це від вас, щоб грати добре, ви часто не вважаєте це умовами підтримки unicode (особливо до тих пір, поки вам це не потрібно. і вдарив ту стіну). І деякі мови, будучи передумовою, не реалізують рядки з базовими масивами простих 8-бітових примітивних символів. Вони випікаються в UTF-8 або UTF-16 або що-у вас є підтримка для вас, і наслідком цього є надзвичайно більший обсяг пам'яті, який часто не потрібен, і більший час на обробку пам'яті, обробка струн, і реалізувати всю логіку, яка йде рука об руку, маніпулюючи кодовими точками.
Результати всього цього полягають у тому, що коли ви робите щось еквівалентне в псевдокоді:
hello = "hello,"
world = " world!"
str = hello + world
Це може бути, незважаючи на всі зусилля, які доклали розробники мови, щоб вони поводилися так, як ви хотіли, - простим як:
a = 1;
b = 2;
shouldBeThree = a + b
У подальшому ви можете прочитати:
Фраза "середня операція", ймовірно, скорочена для однієї операції теоретичної машини з збереженою програмою з випадковим доступом . Це теоретична машина, яку прийнято використовувати для аналізу часу виконання різних алгоритмів.
Узагальнені операції зазвичай приймаються як завантаження, додавання, віднімання, зберігання, розгалуження. Можливо також читати, друкувати та зупиняти.
Але для більшості рядкових операцій потрібно кілька таких основних операцій. Наприклад, для дублювання рядка зазвичай потрібна операція копіювання, а отже, і ряд операцій, пропорційний довжині рядка (тобто "лінійний"). Знаходження підрядки в іншому рядку також має лінійну складність.
Це повністю залежить від операції, як представлені рядки та які оптимізації існують. Якщо рядки мають довжину 4 або 8 байтів (і вирівнюються), вони не обов'язково будуть повільнішими - багато операцій були б такими ж швидкими, як і примітиви. Або, якщо всі рядки мають 32-бітний або 64-бітний хеш, багато операцій також будуть настільки ж швидкими (хоча ви сплачуєте хеш-хеш наперед).
Це також залежить від того, що ви маєте на увазі під «повільним». Більшість програм буде обробляти рядки досить швидко для того, що потрібно. Порівняння рядків може бути не настільки швидким, як порівняння двох входів, але лише профілювання виявить, що "повільно" означає для вашої програми.
Дозвольте мені відповісти на запитання. Чому вимова рядка слів займає більше часу, ніж вимова одного слова?