Можно предположить, что работа с неизменяемыми данными с одиночными присваиваниями требует большего объема памяти, потому что вы постоянно создаете новые значения (хотя компиляторы под крышками делают трюки с указателями, чтобы уменьшить эту проблему).
Но я уже несколько раз слышал, что потери в производительности перевешиваются выигрышем в том, что процессор (особенно его контроллер памяти) может использовать тот факт, что память не видоизменяется (так сильно).
Я надеялся, что кто-нибудь сможет пролить свет на то, как это правда (или, если это не так?).
В комментарии к другому посту было упомянуто, что абстрактные типы данных (ADT) имеют отношение к этому, что еще больше удивило меня, как ADT конкретно влияют на то, как процессор взаимодействует с памятью? Это, однако, в стороне, в основном я просто интересуюсь тем, как чистота языка обязательно влияет на производительность процессора и его кешей и т. Д.
источник
let a = [1,2,3] in let b = 0:a in (a, b, (-1):c)
разделении снижают требования к памяти, но зависит от определения(:)
и ,[]
а не компилятор. Я думаю? Не уверен насчет этого.Ответы:
Преимущество в том, что этот факт избавляет компилятор от использования мембранных инструкций при доступе к данным.
Видите ли, когда к данным получают доступ из разных потоков, в многоядерном процессоре это происходит примерно так: разные потоки работают на разных ядрах, каждый из которых использует свой собственный (локальный для своего ядра) кэш - копию некоторого глобального кеша.
Если данные являются изменяемыми и программисту необходимо, чтобы они были согласованы между различными потоками, необходимо принять меры для обеспечения согласованности. Для программиста это означает использование конструкций синхронизации, когда они обращаются (например, читают) к данным в определенном потоке.
Для компилятора конструкция синхронизации в коде означает, что ему нужно вставить мембранную инструкцию , чтобы убедиться, что изменения, внесенные в копию данных на одном из ядер, правильно распространяются («публикуются»), чтобы гарантировать кэширование на других ядрах. иметь одну и ту же (актуальную) копию.
Несколько упрощенно смотрите примечание ниже , вот что происходит на многоядерных процессорах для мембран:
Видите ли, все ядра ничего не делают, пока данные копируются между глобальным и локальным кэшем . Это необходимо для обеспечения правильной синхронизации изменяемых данных (поточно-ориентированных). Если имеется 4 ядра, все 4 останавливаются и ждут, пока кешируются данные. Если их 8, все 8 останавливаются. Если их 16 ... ну, у вас есть 15 ядер, которые ничего не делают в ожидании того, что нужно сделать на одном из них.
Теперь давайте посмотрим, что происходит, когда данные неизменны? Независимо от того, какой поток обращается к нему, он гарантированно будет одинаковым. Для программиста это означает, что нет необходимости вставлять конструкции синхронизации, когда они обращаются (читают) к данным в определенном потоке.
Для компилятора это, в свою очередь, означает, что нет необходимости вставлять мембранную инструкцию .
В результате доступ к данным не должен останавливать ядра и ждать, пока данные будут записываться между глобальным и локальным кэшем. Это преимущество того факта, что память не видоизменяется .
Обратите внимание, что несколько упрощенное объяснение, приведенное выше, устраняет некоторые более сложные негативные последствия изменчивости данных, например, при конвейерной обработке . Чтобы гарантировать требуемое упорядочение, ЦПУ должен лишить законной силы коллекторы, затронутые изменениями данных - это еще одно снижение производительности. Если это реализуется путем простой (и, следовательно, надежной) отмены всех конвейеров, то отрицательный эффект еще более усиливается.
источник