불변성이 JavaScript의 성능을 저하 시킵니까?


88

JavaScript에서 데이터 구조를 불변으로 취급하는 경향이 최근에 보입니다. 예를 들어 객체의 단일 속성을 변경해야하는 경우 새 속성을 사용하여 완전히 새로운 객체를 만들고 기존 객체의 다른 모든 속성을 복사하여 기존 객체를 가비지 수집하는 것이 좋습니다. (어쨌든 내 이해입니다.)

내 초기 반응은 성능에 좋지 않은 것 같습니다.

그러나 Immutable.jsRedux.js 와 같은 라이브러리 는 나보다 똑똑한 사람들이 작성했으며 성능에 대한 강한 관심이있는 것처럼 보이므로 쓰레기 (및 성능 영향)에 대한 나의 이해가 잘못되었는지 궁금합니다.

내가 잃어버린 불변성에 성능상의 이점이 있습니까? 그리고 너무 많은 쓰레기를 만드는 단점을 능가합니까?


8
불변성 (때로는)에는 성능 비용이 있기 때문에 성능에 대한 큰 관심을 가지고 있으며 가능한 한 그 성능 비용을 최소화하려고합니다. 불변성은 그 자체만으로도 멀티 스레드 코드를보다 쉽게 ​​작성할 수 있다는 점에서 성능상의 이점이 있습니다.
Robert Harvey

8
필자의 경험에 따르면 성능은 두 가지 시나리오, 즉 1 초에 30 회 이상 작업을 수행 할 때와 두 가지 시나리오에 대해 유효한 관심사 일뿐입니다. 두 번째는 실행 시마다 효과가 증가 할 때입니다 (Windows XP는 한 번 Windows Update 시간이 걸리는 버그를 발견했습니다) O(pow(n, 2))에 대한 역사의 모든 갱신 ) 대부분의 다른 코드는 이벤트에 대한 즉각적인 반응이다.; 클릭, API 요청 또는 이와 유사하며 실행 시간이 일정하다면 개체 수를 정리하는 것이 중요하지 않습니다.
Katana314

4
또한 불변 데이터 구조의 효율적인 구현이 존재한다고 생각하십시오. 아마도 이것들은 변경 가능한 것만 큼 효율적이지 않지만 순진한 구현보다 여전히 효율적입니다. 예를 들어 Chris Okasaki의 순수 기능 데이터 구조
Giorgio

1
@ Katana314 : 30 번 이상 나를 위해 성능에 대한 걱정을 정당화하기에는 충분하지 않습니다. node.js에 쓴 작은 CPU 에뮬레이터를 이식하고 node는 약 20MHz (초당 2 천만 번)에서 가상 CPU를 실행했습니다. 따라서 초당 1000 회 이상 무언가를 수행하는 경우 성능에 대해서만 걱정할 것입니다 (그런데도 한 번에 10 개 이상을 편안하게 수행 할 수 있다는 것을 알고 있기 때문에 초당 1000000 작업을 수행 할 때까지 실제로 걱정하지 않습니다) .
slebetman

2
@RobertHarvey "다중 스레드 코드를보다 쉽게 ​​작성할 수 있다는 점에서 면역 자체만으로도 성능상의 이점이 있습니다." 그것은 전적으로 사실이 아니며, 불변성은 실제 결과없이 매우 널리 퍼질 수 있습니다. 가변 환경에서는 매우 안전하지 않습니다. 이것은 O(1)배열 슬라이싱과 O(log n)바이너리 트리에의 삽입 과 같은 생각을 제공 하지만 여전히 오래된 것을 자유롭게 사용할 수 있으며 또 다른 예는 tails목록의 모든 꼬리를 시간과 공간 tails [1, 2] = [[1, 2], [2], []]만 필요로 O(n)하지만 O(n^2)요소 수에 있습니다
세미콜론

답변:


59

예를 들어 객체의 단일 속성을 변경해야하는 경우 새 속성을 사용하여 완전히 새로운 객체를 만들고 기존 객체의 다른 모든 속성을 복사하여 기존 객체를 가비지 수집하는 것이 좋습니다.

불변성이 없으면 다른 범위 사이에서 객체를 전달해야 할 수 있으며 객체가 언제 변경되는지 미리 알 수 없습니다. 따라서 원치 않는 부작용을 피하기 위해 "경우에 따라"개체의 전체 복사본을 만들기 시작하고 속성을 전혀 변경할 필요가없는 경우에도 해당 복사본을 전달합니다. 그것은 당신의 경우보다 더 많은 쓰레기를 남길 것입니다.

이것이 입증하는 것은 올바른 가상 시나리오를 만들면 특히 성능과 관련하여 무엇이든 증명할 수 있다는 것입니다. 그러나 내 예는 들리는 것처럼 가상적인 것은 아닙니다. 지난달 불변의 데이터 구조를 사용하지 않기로 결정했기 때문에 정확히 그 문제를 우연히 발견 한 프로그램에서 일했습니다. 그리고 나중에 번거롭게 할 가치가 없기 때문에 이것을 리팩토링하는 것을 망설였습니다.

당신이 좋아하는 경우를 볼 때 그래서 이전 SO 포스트에서이 하나 , 질문에 대한 대답은 아마도 분명해진다 - 그것은 의존한다 . 어떤 경우에는 불변성이 성능을 떨어 뜨릴 수 있으며, 어떤 경우에는 그 반대 일 수 있으며, 많은 경우에는 구현이 얼마나 똑똑한 지에 따라 달라지며, 더 많은 경우에는 그 차이를 무시할 수 있습니다.

마지막 참고 사항 : 발생할 수있는 실제 문제는 일부 기본 데이터 구조에 대해 초기 또는 불변성을 결정해야한다는 것입니다. 그런 다음 많은 코드를 작성하고 몇 주 또는 몇 달 후에 결정이 좋은지 또는 나쁜지 알 수 있습니다.

이 상황에 대한 나의 개인적인 경험 규칙은 다음과 같습니다.

  • 기본 또는 기타 변경 불가능한 유형을 기반으로 몇 가지 속성 만있는 데이터 구조를 디자인하는 경우 먼저 변경 불가능 성을 시도하십시오.
  • 큰 (또는 정의되지 않은) 크기, 임의 액세스 및 변경 내용이 포함 된 배열이 포함 된 데이터 유형을 설계하려면 가변성을 사용하십시오.

이 두 극단 사이의 상황에서는 판단을 사용하십시오. 그러나 YMMV.


8
That will leave a lot more garbage than in your case.설상가상으로, 런타임은 무의미한 복제를 감지 할 수 없으므로 (아무도 사용하지 않는 만료 된 불변 객체와 달리) 수집조차 할 수 없습니다.
Jacob Raihle

37

우선, 불변 데이터 구조의 특성은 정확하지 않습니다. 일반적으로 대부분의 데이터 구조는 복사되지 않고 공유 되며 변경된 부분 만 복사됩니다. 이를 영구 데이터 구조 라고합니다 . 대부분의 구현은 영구적 인 데이터 구조를 대부분 활용할 수 있습니다. 성능은 기능 프로그래머가 일반적으로 무시할 수있는 것으로 간주되는 가변 데이터 구조에 충분히 가깝습니다.

둘째, 많은 사람들이 전형적인 명령형 프로그램에서 객체의 일반적인 수명에 대해 상당히 부정확 한 아이디어를 가지고 있음을 발견했습니다. 아마도 이것은 메모리 관리 언어의 인기 때문일 것입니다. 언젠가 앉아서 실제로 오래 지속되는 데이터 구조와 비교하여 얼마나 많은 임시 객체와 방어 사본을 생성하는지 살펴보십시오. 나는 당신이 그 비율에 놀랄 것이라고 생각합니다.

나는 알고리즘이 얼마나 많은 가비지를 생성하는지에 관해 가르치는 함수형 프로그래밍 클래스에 대해 사람들에게 언급했다. 그리고 나는 많은 것을 만드는 동일한 알고리즘의 전형적인 명령형 버전을 보여준다. 어떤 이유로 사람들은 더 이상 그것을 알아 차리지 못합니다.

변수를 넣을 수있는 유효한 값이 될 때까지 변수를 만드는 것을 공유하고 장려하지 않기 때문에 불변성은 더 명확한 코딩 방법과 더 긴 데이터 구조를 장려하는 경향이 있습니다. 알고리즘에 따라 가비지 수준이 낮지 않은 경우가 종종 있습니다.


8
"... 그런 다음에도 같은 알고리즘의 전형적인 명령형 버전을 보여줍니다." 이. 또한,이 스타일을 처음 접하는 사람들, 특히 일반적으로 기능적인 스타일을 처음 접하는 사람들은 처음에는 최적화되지 않은 기능 구현을 생성 할 수 있습니다.
wberry

1
"변수 생성 감지"기본 동작이 할당 / 암시 적 구성시 복사 인 언어에만 유효하지 않습니까? JavaScript에서 변수는 식별자 일뿐입니다. 그것은 그 자체로는 대상이 아닙니다. 여전히 어딘가에 공간을 차지하지만 무시할 수 있습니다 (특히 대부분의 JavaScript 구현에서 내 지식으로는 함수 호출에 여전히 스택을 사용합니다. 재귀가 많지 않은 한 대부분의 경우 동일한 스택 공간을 재사용하게됩니다) 임시 변수). 불변성은 그 측면과 관련이 없습니다.
JAB

33

이미 큰 답을 가지고이 Q & A에 늦었지만 메모리의 하위 레벨 관점에서 물건을 보는 데 익숙한 외국인으로 침입하고 싶었습니다.

나는 불변의 디자인, 심지어 C 관점과 오늘날 우리가 가지고있는이 야수적인 하드웨어를 효과적으로 프로그래밍 할 수있는 새로운 방법을 찾는 관점에서 매우 기뻐합니다.

느리게 / 빠르게

속도가 느려지는지에 대한 질문에 대해서는 로봇이 대답합니다 yes. 이런 종류의 매우 기술적 개념 수준에서 불변성은 일을 더 느리게 할 수 있습니다. 하드웨어는 산발적으로 메모리를 할당하지 않고 기존 메모리를 대신 수정할 수있는 경우에 가장 좋습니다 (시간적 지역 성과 같은 개념을 갖는 이유).

그러나 실질적인 대답은 maybe입니다. 성능은 여전히 ​​사소한 코드베이스의 생산성 지표입니다. 우리는 일반적으로 버그를 무시하더라도 경쟁 조건을 넘어서는 끔찍한 유지 보수 코드베이스를 가장 효율적으로 찾지 않습니다. 효율성은 종종 우아함과 단순함의 함수입니다. 미세 최적화의 피크는 다소 상충 될 수 있지만 일반적으로 가장 작고 중요한 코드 섹션을 위해 예약되어 있습니다.

불변 비트 및 바이트 변환

우리는 같은 개념 선 X 경우, 낮은 수준의 관점에서 오는 objectsstrings그것의 중심, 등등과 서로 다른 속도 / 크기 특성을 갖는 메모리의 다양한 형태 (속도 및 메모리 하드웨어의 크기는 통상적 인 단지 비트 바이트 상호 배타적).

여기에 이미지 설명을 입력하십시오

컴퓨터의 메모리 계층은 위의 다이어그램과 같이 동일한 메모리 청크에 반복적으로 액세스 할 때 자주 사용합니다. 자주 액세스하는 메모리 청크를 가장 빠른 형태의 메모리 (L1 캐시)로 유지하기 때문입니다. 거의 레지스터만큼 빠릅니다). 동일한 메모리에 반복적으로 액세스하거나 (여러 번 재사용) 청크의 다른 섹션에 반복적으로 액세스 할 수 있습니다 (예 : 해당 메모리 청크의 다양한 섹션에 반복적으로 액세스하는 연속 청크의 요소를 반복).

이 메모리를 수정하면 다음과 같이 측면에 완전히 새로운 메모리 블록을 만들려고하면 해당 프로세스에서 렌치를 던집니다.

여기에 이미지 설명을 입력하십시오

...이 경우, 새로운 메모리 블록에 액세스하려면 강제적 인 페이지 폴트와 캐시 미스가 가장 빠른 형태의 메모리 (레지스터까지)로 다시 이동할 수 있습니다. 실제 성능을 저하시킬 수 있습니다.

그러나 미리 할당 된 메모리의 예약 풀을 사용하여이를 완화 할 수있는 방법이 있습니다.

큰 집계

약간 더 높은 수준의 관점에서 발생하는 또 다른 개념적 문제는 단순히 대량의 집계를 불필요하게 대량 복사하는 것입니다.

지나치게 복잡한 다이어그램을 피하기 위해이 간단한 메모리 블록이 다소 비싸다고 상상해보십시오 (믿을 수 없을 정도로 제한된 하드웨어에서는 UTF-32 문자 일 수 있음).

여기에 이미지 설명을 입력하십시오

이 경우 "HELP"를 "KILL"로 바꾸고이 메모리 블록을 변경할 수없는 경우 일부만 변경된 경우에도 완전히 새로운 블록을 만들어 고유 한 새 객체를 만들어야합니다. :

여기에 이미지 설명을 입력하십시오

우리의 상상력을 아주 조금 늘리면, 하나의 작은 부분을 독특하게 만들기위한 다른 모든 종류의 깊은 사본은 상당히 비쌀 수 있습니다 (실제 경우이 메모리 블록은 문제를 제기하기에 훨씬 더 클 것입니다).

그러나 이러한 비용에도 불구하고 이러한 종류의 디자인은 인적 오류가 덜 발생하는 경향이 있습니다. 순수한 기능을 가진 기능적 언어로 일한 사람은 아마도 이것을 이해할 수 있습니다. 특히 세계에서 신경 쓰지 않고 그러한 코드를 멀티 스레드 할 수있는 멀티 스레드 경우에 특히 그렇습니다. 일반적으로 휴먼 프로그래머는 상태 변경, 특히 현재 기능 범위 밖의 상태에 외부 부작용을 일으키는 변경을 넘어 트립하는 경향이 있습니다. 이러한 경우 외부 오류 (예외)를 복구하더라도 믹스의 변경 가능한 외부 상태 변경으로 인해 매우 어려울 수 있습니다.

이 중복 복사 작업을 완화하는 한 가지 방법은 이러한 메모리 블록을 다음과 같이 문자에 대한 포인터 (또는 참조) 모음으로 만드는 것입니다.

사과, 나는 L다이어그램을 만드는 동안 우리가 독특하게 만들 필요가 없다는 것을 깨닫지 못했습니다 .

파란색은 얕은 복사 된 데이터를 나타냅니다.

여기에 이미지 설명을 입력하십시오

... 불행히도, 이것은 문자 당 포인터 / 참조 비용을 지불하는 데 엄청나게 비쌀 것입니다. 더욱이, 우리는 주소 공간 전체에 문자의 내용을 분산시켜 페이지 결함 및 캐시 미스의 보트로드 형태로 지불하여 결국 전체 솔루션을 복사하는 것보다이 솔루션을 훨씬 더 악화시킬 수 있습니다.

이 문자들을 연속적으로 할당하려고하더라도, 기계는 문자에 대한 8 개의 문자와 8 개의 포인터를 캐시 라인에로드 할 수 있다고 말합니다. 새 문자열을 순회하기 위해 다음과 같이 메모리를로드합니다.

여기에 이미지 설명을 입력하십시오

이 경우 이상적으로는 3 개만 필요할 때이 문자열을 통과하기 위해 7 개의 서로 다른 캐시 라인의 연속 메모리를로드해야합니다.

데이터 청크

위의 문제를 완화하기 위해 동일한 기본 전략을 적용 할 수 있지만 대략 8 자 수준으로 적용 할 수 있습니다.

여기에 이미지 설명을 입력하십시오

결과적으로 4 개의 캐시 라인에 해당하는 데이터 (3 개의 포인터에 대해 1 개, 문자에 대해 3 개)를로드하여 이론적으로 최적 인 1 개에 불과한이 문자열을 통과해야합니다.

그래서 전혀 나쁘지 않습니다. 약간의 메모리 낭비가 있지만 메모리가 충분하며 추가 메모리가 자주 액세스되지 않는 차가운 데이터 일 경우 더 많이 사용하더라도 속도가 느려지지 않습니다. 메모리 사용과 속도가 줄어드는 경우가 많고 한 페이지 나 캐시 라인에 더 많은 메모리를 넣고 제거하기 전에 모두 액세스하려는 경우가 많고 연속적인 데이터에만 해당됩니다. 이 표현은 캐시 친화적입니다.

속도

따라서 위와 같은 표현을 사용하면 상당히 균형 잡힌 성능을 얻을 수 있습니다. 변경 불가능한 데이터 구조의 가장 성능이 중요한 사용은 수정되지 않은 조각을 얕게 복사하면서 청크 한 데이터 조각을 수정하고 프로세스에서 고유하게 만드는 특성을 취합니다. 또한 다중 스레드 컨텍스트에서 얕은 복사 된 조각을 안전하게 참조하기 위해 원자 작업에 약간의 오버 헤드가 있음을 의미합니다 (아마도 일부 원자 참조 계산이 진행 중일 수 있음).

그러나이 두툼한 데이터가 대략적으로 충분한 수준으로 표시되는 한, 이러한 오버 헤드가 줄어들고 사소한 경우에도 외부 측면이없는 순수한 형태로 더 많은 기능을 코딩하고 멀티 스레딩하는 안전과 편의성을 제공합니다. 효과.

신규 및 기존 데이터 유지

불변성이 성능 관점에서 잠재적으로 가장 도움이되는 것으로 보았을 때 (실제적인 의미에서) 우리는 목표가 새로운 것을 만들어내는 가변적 인 환경에서 고유하게 만들기 위해 큰 데이터의 전체 사본을 만들려고 할 때입니다 우리는 신중하고 불변의 디자인으로 약간의 비트와 조각을 독특하게 만들 수있을 때 이미 새롭고 오래된 것을 유지하려는 방식으로 존재합니다.

예 : 시스템 실행 취소

이에 대한 예는 실행 취소 시스템입니다. 데이터 구조의 일부를 변경하여 취소 할 수있는 원래 양식과 새 양식을 모두 유지하려고 할 수 있습니다. 데이터 구조의 작고 수정 된 섹션 만 고유하게 만드는 이러한 종류의 불변 디자인으로 추가 된 고유 부분 데이터의 메모리 비용 만 지불하면서 이전 데이터의 사본을 실행 취소 항목에 간단히 저장할 수 있습니다. 이는 생산성 (실행 취소 시스템의 구현을 케이크로 만드는 것)과 성능의 매우 효과적인 균형을 제공합니다.

고급 인터페이스

그러나 위의 경우에는 어색한 것이 발생합니다. 로컬 종류의 함수 컨텍스트에서 변경 가능한 데이터는 종종 가장 쉽고 수정하기 쉬운 것입니다. 결국 배열을 수정하는 가장 쉬운 방법은 종종 배열을 반복하고 한 번에 하나의 요소를 수정하는 것입니다. 배열을 변환하기 위해 선택할 수있는 높은 수준의 알고리즘이 많고 수정 된 부분이 모두 생성되는 동안 이러한 뭉툭한 얕은 복사본이 만들어 지도록 적절한 알고리즘을 선택해야한다면 지적 오버 헤드가 증가 할 수 있습니다. 독창적.

아마도이 경우 가장 쉬운 방법은 변경 불가능한 버퍼를 함수 컨텍스트 (일반적으로 우리를 트립하지 않는)의 컨텍스트 내에서 로컬로 사용하여 변경 사항을 원자 적으로 변경하여 데이터 구조에 원자 적으로 변경하여 새로운 불변 ​​사본을 얻는 것입니다 (일부 언어 호출이라고 생각합니다) 이 "과도 현상") ...

... 또는 단순히 데이터에 대한 상위 및 상위 수준 변환 함수를 모델링하여 변경 가능한 버퍼를 수정하고 변경 가능한 논리없이 구조에 커밋하는 프로세스를 숨길 수 있습니다. 어쨌든, 이것은 아직 광범위하게 탐구 된 영역이 아니며, 이러한 데이터 구조를 변환하는 방법에 대한 의미있는 인터페이스를 찾기 위해 불변 디자인을 더 수용하면 작업이 중단됩니다.

데이터 구조

여기서 발생하는 또 다른 사항은 성능에 중요한 컨텍스트에서 사용되는 불변성이 청크 크기가 너무 작지 않고 너무 크지 않은 데이터 구조를 청크 데이터로 분해하기를 원할 것입니다.

링크 된 목록은이를 수용하기 위해 약간 변경하고 롤링되지 않은 목록으로 전환 할 수 있습니다. 크고 연속적인 배열은 임의 액세스를 위해 모듈로 색인을 사용하여 포인터 배열로 연속 된 덩어리로 바뀔 수 있습니다.

잠재적으로 데이터 구조를 보는 방식을 흥미로운 방식으로 변경하는 한편, 이러한 데이터 구조의 수정 기능을 사용하여 부피를 얕게 복사하여 여기에 약간의 비트를 얕게 복사하고 다른 비트를 고유하게 만드는 복잡성을 숨길 수 있습니다.

공연

어쨌든, 이것은 주제에 대한 저의 작은 관점입니다. 이론적으로, 불변성의 비용은 매우 큰 것에서 작은 것까지의 비용을 가질 수 있습니다. 그러나 매우 이론적 인 접근 방식이 항상 애플리케이션을 빠르게 만드는 것은 아닙니다. 확장 가능하게 만들 수 있지만 실제 속도는 종종보다 실용적인 사고 방식을 수용해야합니다.

실제적인 관점에서 볼 때 성능, 유지 관리 성 및 안전성과 같은 특성은 특히 매우 큰 코드베이스의 경우 한 가지 큰 흐리게 표시되는 경향이 있습니다. 절대적인 의미에서 성능은 불변성으로 인해 저하되지만 생산성 및 안전성 (스레드 안전성 포함)에 대한 이점을 주장하기는 어렵습니다. 개발자가 버그에 얽매이지 않고 코드를 조정하고 최적화 할 시간이 더 많기 때문에 이러한 성능이 향상되면 실제 성능이 향상 될 수 있습니다.

그래서 나는이 실제적인 의미에서, 불변의 데이터 구조가 실제로 있다고 생각 도움 이 소리 홀수로, 많은 경우에 성능을. 이상적인 세계는 불변 데이터 구조와 가변 구조의 혼합을 추구 할 수 있으며, 가변 구조는 일반적으로 매우 로컬 범위 (예 : 함수에 국지)에서 사용하기에 매우 안전하지만 불변의 구조는 외부를 피할 수 있습니다 데이터 구조에 대한 모든 변경 사항을 철저한 영향을 미치고 경쟁 조건의 위험없이 새 버전을 생성하는 원자 작업으로 바꿉니다.


11

ImmutableJS는 실제로 매우 효율적입니다. 예를 들어 보면 :

var x = {
    Foo: 1,
    Bar: { Baz: 2 }
    Qux: { AnotherVal: 3 }
}

위의 객체를 변경할 수 없다면 'Baz'속성 값을 수정하십시오.

var y = x.setIn('/Bar/Baz', 3);
y !== x; // Different object instance
y.Bar !== x.Bar // As the Baz property was changed, the Bar object is a diff instance
y.Qux === y.Qux // Qux is the same object instance

이렇게하면 딥 오브젝트 모델의 근사한 성능 향상을 얻을 수 있습니다. 여기서 루트 경로에있는 오브젝트의 값 유형 만 복사하면됩니다. 객체 모델이 크고 변경 사항이 작을수록 많은 객체를 공유하게되므로 불변 데이터 구조의 메모리 및 CPU 성능이 향상됩니다.

다른 답변에서 말했듯이 이것을 x조작 할 수있는 기능으로 전달하기 전에 방어 적으로 복사하여 동일한 보장을 제공하는 것과 대조 하면 성능이 크게 향상됩니다.


4

곧바로, 불변 코드는 객체 생성 오버 헤드를 가지므로 속도가 느려집니다. 그러나 변경 가능한 코드를 효율적으로 관리하기가 매우 어려운 상황이 많고 (비록 수비가 많이 발생하고, 비용도 많이 듭니다), 객체를 '복사'하는 비용을 줄이기위한 많은 영리한 전략이 있습니다. 다른 사람들이 언급했듯이

카운터와 같은 개체가 있고 1 초에 여러 번 증가하는 경우 해당 카운터를 변경할 수없는 경우 성능이 저하 될 수 있습니다. 응용 프로그램의 여러 부분에서 읽은 개체가 있고 각 개체마다 약간 다른 개체 복제본을 갖고 싶은 경우 좋은 개체를 사용하여 성능이 뛰어난 방식으로 개체를 조정하는 것이 훨씬 쉬워집니다 불변의 객체 구현.


4

이 질문에 덧붙이려면 (이미 훌륭한 답변이 됨) :

짧은 대답은 ' 예'입니다 . 기존 오브젝트를 변경하는 대신 오브젝트를 작성하기 만하면 성능이 저하되어 오브젝트 작성 오버 헤드가 증가합니다.


그러나 긴 대답은 실제로아닙니다 .

실제 런타임 관점에서 볼 때 JavaScript에서는 이미 많은 런타임 객체를 만들었습니다. 함수와 객체 리터럴은 JavaScript의 모든 곳에 있으며 아무도 그 사용에 대해 두 번 생각하지 않는 것 같습니다. 나는 인용이 없기 때문에 객체 생성이 실제로 매우 저렴하다고 주장하므로 독립형 인수로 사용하지 않을 것입니다.

나를 위해, 가장 큰 '성능'증가는 런타임 성능이 아니라 개발자 성능입니다. Real World (tm) 응용 프로그램에서 작업하면서 처음 배운 점 중 하나는 변경 가능성이 실제로 위험하고 혼란 스럽다는 것입니다. 나는 응용 프로그램의 반대쪽에서 돌연변이로 밝혀 질 때 모호한 버그를 일으키는 원인을 해결하려고 시도하는 동시성 유형이 아닌 스레드를 추적하는 데 많은 시간을 잃었습니다!

불변성을 사용하면 추론하기가 훨씬 쉬워집니다. X 객체가 수명 기간 동안 변경 되지 않을 것임을 즉시 알 수 있으며 변경하는 유일한 방법은 복제하는 것입니다. 나는 이것이 변경 가능성이 가져올 수있는 마이크로 최적화보다 훨씬 (특히 팀 환경에서) 더 중요하게 생각합니다.

예외, 특히 위에서 언급 한 데이터 구조가 있습니다. 배열과 동일하게 생성 후 맵을 변경하고 싶었던 시나리오를 거의 보지 못했습니다. 더 큰 데이터 구조를 다루는 경우 변경 가능성 높아질 수 있습니다 . JavaScript의 모든 객체는 값이 아닌 참조로 전달됩니다.


즉, 위에서 언급 한 한 가지 점은 GC와 중복을 감지 할 수 없다는 점입니다. 이것은 합법적 인 문제이지만, 제 생각에는 메모리가 문제 일 때에 만 문제가되고, 클로저의 순환 참조와 같이 코너에 자신을 코딩하는 훨씬 쉬운 방법이 있습니다.


궁극적으로, 내가 가진 불변의 코드베이스가하는 것을 선호 아주 (있는 경우) 몇 가지 변경 가능한 부분을 사방에 가변성이보다 약간 낮은 성능이 좋은 수. 불변성이 어떤 이유로 성능에 대한 우려가되는 경우 언제든지 나중에 최적화 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.