Если функция использует локальные, частные (для функции) изменяемые структуры данных, распараллеливание не затрагивается.Поэтому, если функция map
внутренне создает массив размером с список и выполняет итерацию по его элементам, заполняющим массив, вы все равно можете запускать map
100 раз одновременно в одном и том же списке и не беспокоиться, поскольку каждый экземпляр map
будет иметь собственный закрытый массив.Поскольку ваш код не может видеть содержимое массива до тех пор, пока он не будет заполнен, он фактически чистый (помните, что на каком-то уровне ваш компьютер должен фактически изменять состояние ОЗУ).
С другой стороны, еслифункция использует глобальные изменяемые структуры данных, параллелизм может быть затронут.Например, допустим, у вас есть функция Memoize
.Очевидно, что весь смысл в том, чтобы поддерживать некое глобальное состояние (хотя оно и «глобально» в том смысле, что оно не локально для вызова функции, оно все еще «приватно» в том смысле, что оно не доступно вне функции), чтобыон не должен запускать функцию несколько раз с одними и теми же аргументами, но он все еще чистый, потому что одни и те же входные данные всегда будут давать одинаковые выходные данные.Если ваша структура данных кэша является поточно-ориентированной (например, ConcurrentDictionary
), вы все равно можете запускать свою функцию параллельно с самой собой.Если нет, то вы могли бы утверждать, что функция не является чистой, потому что она имеет побочные эффекты, которые наблюдаются при одновременном запуске.
Я должен добавить, что в F # это обычная техника, которая начинается с чисто функциональной подпрограммызатем оптимизируйте его, используя изменяемое состояние (например, кэширование, явное зацикливание), когда профилирование показывает, что оно слишком медленное.