JavaScript는 실행되는 하드웨어에서 매우 동떨어져 있다고 느낄 수 있지만 제한된 경우에는 낮은 수준으로 생각하는 것이 여전히 유용할 수 있습니다.
루프 최적화에 관한 Kafeel Ahmad의 최근 게시물에서는 다양한 루프 성능 개선 기술을 자세히 설명했습니다. 그 기사 덕분에 그 주제에 대해 생각하게 됐어요
이 문제를 해결하기 위해 웹 개발에서 고려해야 할 기술은 거의 없습니다. 또한 너무 일찍 최적화에 집중하면 코드 작성이 더 어려워지고 유지 관리가 훨씬 더 어려워질 수 있습니다. 해당 지식을 직접 적용할 수 없더라도 낮은 수준의 기술을 살펴보면 도구와 작업 전반에 대한 통찰력을 얻을 수 있습니다.
루프 풀기는 기본적으로 루프 내부의 논리를 복제하므로 각 루프 동안 여러 작업을 수행합니다. 특별한 경우에는 루프의 코드를 길게 만들면 더 빠르게.
할 수 있습니다.일부 작업을 하나씩 그룹으로 의도적으로 수행하면 컴퓨터가 더 효율적으로 작동할 수 있습니다.
아주 간단한 예를 들어보겠습니다. 배열의 값을 합산하는 것입니다.
처음에는 매우 이상하게 보일 수 있습니다. 우리는 더 많은 변수를 관리하고 간단한 예에서는 발생하지 않는 추가 작업을 수행하고 있습니다. 어떻게 이렇게 빨라질 수 있나요?!
다양한 데이터 크기와 다중 실행은 물론 순차 또는 인터리브 테스트에 대해 몇 가지 비교를 실행했습니다. ParallelSum 성능은 다양했지만 매우 작은 데이터 크기에 대한 일부 이상한 결과를 제외하면 거의 항상 더 좋았습니다. Chrome의 V8 엔진을 기반으로 구축된 RunJS를 사용하여 이를 테스트했습니다.
다양한 데이터 크기로 인해 매우 대략 다음과 같은 결과가 나왔습니다.
그런 다음 다양한 브라우저에서 시도하기 위해 100만 개의 레코드가 포함된 JSPerf를 만들었습니다. 직접 시도해 보세요!
Chrome은 RunJS 테스트에서 예상한 대로 simpleSum보다 두 배 빠르게 ParallelSum을 실행했습니다.
Safari는 백분율과 초당 작업 수 측면에서 Chrome과 거의 동일했습니다.
동일 시스템의 Firefox는 simpleSum에 대해 거의 동일한 성능을 발휘했지만 ParallelSum은 약 15% 더 빨랐을 뿐 두 배 빠르지는 않았습니다.
이 변형으로 인해 더 많은 정보를 찾게 되었습니다. 확실한 것은 아니지만 루프 풀기와 관련된 JS 엔진 문제 중 일부를 논의하는 2016년의 StackOverflow 주석을 발견했습니다. 엔진과 최적화가 우리가 예상하지 못한 방식으로 코드에 어떤 영향을 미칠 수 있는지에 대한 흥미로운 시각입니다.
한 변수와 두 변수 사이에 눈에 띄는 차이가 있는지 확인하기 위해 단일 작업에 두 값을 추가하는 세 번째 버전도 시도했습니다.
짧은 답변: 아니요. 두 개의 "병렬" 버전은 서로 보고된 오류 범위 내에 있었습니다.
JavaScript는 단일 스레드이지만, 특정 조건이 충족되면 기반의 인터프리터, 컴파일러 및 하드웨어가 최적화를 수행할 수 있습니다.
간단한 예에서 작업은 어떤 데이터를 가져올지 알기 위해 i 값이 필요하고, 업데이트하려면 최신 sum 값이 필요합니다. 각 루프에서 이러한 두 가지 변경 사항이 모두 변경되므로 컴퓨터는 더 많은 데이터를 얻으려면 루프가 완료될 때까지 기다려야 합니다. i += 1이 무엇을 할 것인지는 우리에게 명백해 보일 수 있지만, 컴퓨터는 대부분 "값이 변경됩니다. 나중에 다시 확인하세요"라고 이해하므로 최적화하는 데 어려움이 있습니다.
저희 병렬 버전은 i의 각 값에 대해 여러 데이터 항목을 로드합니다. 여전히 각 루프의 합계에 의존하지만 주기당 두 배의 데이터를 로드하고 처리할 수 있습니다. 하지만 그렇다고 해서 두 배 빠른 속도.
가 실행된다는 의미는 아닙니다.루프 풀기가 작동하는 이유를 이해하기 위해 컴퓨터의 하위 수준 작동을 살펴봅니다. 슈퍼 스칼라 아키텍처를 갖춘 프로세서에는 동시 작업을 수행하기 위한 여러 파이프라인이 있을 수 있습니다. 서로 의존하지 않는 작업이 가능한 한 빨리 발생할 수 있도록 비순차적 실행을 지원할 수 있습니다. 일부 작업의 경우 SIMD는 여러 데이터에 대해 동시에 하나의 작업을 수행할 수 있습니다. 그 외에도 캐싱, 데이터 가져오기 및 분기 예측을 시작합니다...
하지만 이것은 JavaScript 기사입니다! 우리는 그렇게 깊이 들어가지 않을 것입니다. 프로세서 아키텍처에 대해 더 알고 싶다면 Anandtech의 훌륭한 심층 분석을 참조하세요.
循環展開並不是魔法。由於程式或資料大小、操作複雜性、電腦體系結構等原因,會出現限制和收益遞減。但我們只測試了一兩個操作,現代電腦通常支援四個或更多執行緒。
為了嘗試一些更大的增量,我製作了另一個包含1、2、4 和10 條記錄的JSPerf,並在運行macOS 14.5 Sonoma 的Apple M1 Max MacBook Pro 和運行Windows 11 的AMD Ryzen 9 3950X PC上運行。
一次處理 10 筆記錄比基本循環快 2.5-3.5 倍,但僅比在 Mac 上處理 4 筆記錄快 12-15%。在 PC 上,我們仍然看到 1 到 2 筆記錄之間的效能提升了 2 倍,但 10 筆記錄僅比 4 筆記錄快 2%,這對於 16 核心處理器來說是我無法預測的。平台和更新
對於某些效能規模,目前推出的 HP 入門級 Chromebook 配備 Intel Celeron N4120 處理器。這大致相當於我的 2013 Core i5-4250U MacBook Air。在綜合基準測試中,它的表現僅為 M1 Max 的九分之一。在那台 2013 年 MacBook Air 上,運行最新版本的 Chrome,
4 記錄功能 比 10 記錄功能快,但仍然只比單記錄功能快 60%! 瀏覽器和標準也在不斷變化。例行的瀏覽器更新或不同的處理器架構可能會使最佳化的程式碼比常規循環慢。當您發現自己進行深度最佳化時,您可能需要確保您的最佳化與消費者相關,並且保持相關性
.這讓我想起了 Nicholas Zakas 寫的《高效能 JavaScript》一書,我在 2012 年讀過這本書。這是一本很棒的書,包含了許多見解。然而,到 2014 年,書中指出的許多重大效能問題已透過瀏覽器引擎更新得到解決或大幅減少,我們能夠將更多精力集中在編寫可維護的程式碼上。 如果您想保持效能最佳化的領先地位,請為更改和定期驗證做好準備。
過去的教訓在研究這個主題時,我遇到了 2000 年的 Linux 核心郵件列表線程,該線程關於刪除一些循環展開優化,最終提高了應用程式效能。它包括這個仍然相關的點(強調我的):
最重要的是,我們對什麼快、什麼慢的直覺假設常常是錯誤的,
特別是考慮到過去幾年 CPU 發生了多大的變化。
– Theodore Ts'o不過,我希望您喜歡我的漫談,也許將來您會記住有關性能優化的注意事項。結論
有時您可能需要從循環中擠出性能,如果您正在處理足夠的項目,這可能是您這樣做的方法之一。了解這類最佳化固然很好,但對於大多數工作來說,您並不需要它™。
위 내용은 JavaScript에서 루프 풀기?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!