2014-11-07 2 views
4

어제 두 개의 루프를 사용하여 두 개의 배열 (배열은 동일 함)의 개체를 비교하는 작은 코드 블록을 작성했습니다. 그러나, 나는이 함수형 프로그래밍에왔다중첩 for 루프 성능 대 자바 스크립트의 배열 함수

var result = [] 
for (var i = 0; i < res.length; i++) { 
    var tempObj = {} 
    tempObj.baseName = res[i].name 
    tempObj.cnt = res[i].cnt 
    tempObj.matches = [] 
    for (var j = 0; j < compareArr.length; j++) { 
     if(natural.LevenshteinDistance(res[i].name, compareArr[j].name) === options.distance) { 
      tempObj.matches.push(compareArr[j]) 
     } 
    } 
    if (tempObj.matches.length > 0) { 
     result.push(tempObj) 
    } 
} 

이 함께 지난 몇 달 킥과 더 많은 기능 접근 방식을 사용하여 코드 블록을 다시 결정하고 결국 :

var result = res. 
    map(function(baseItem) { 
     baseItem.matches = compareArr. 
      reduce(function(acc, compItem) { 
       if(natural.LevenshteinDistance(baseItem.name, compItem.name) === options.distance) { 
        acc.push(compItem) 
       } 
       return acc 
      }, []) 
      return baseItem 
     }). 
     filter(function(item) { 
      return item.matches.length > 0 
     }) 

내 경로가 같은 느낌 그러나 조금 더 느리게 응답했지만, 데이터가 반복되는 것은 수십만 개의 항목을 포함 할 수있는 데이터베이스 쿼리의 결과이며 아무런 이유없이 서버의 성능을 저하시키지 않으려 고하고 싶었습니다. 그래서 jsperf에 함수를 연결했고 the results은 슬프다. for 루프는 약 2,600 ops/sec에서 실행되고 두 번째 블록은 약 500 ops/sec에서 실행됩니다. :(

이 문제는 잘못 서면 그것을 개선 속도를 제기 할 수 있습니다 내 두 번째 블록이다? 그렇지 않으면,이 정상인가? 나는 자바 스크립트 기능적인 스타일 **을 밀어 점점 더 많은 사람들을 참조하십시오.

나는 함수형 언어를 배우고 즐길 그냥 내 자바 스크립트에서 그것을두고해야 하는가? 스타일의 이름으로 성능을 아프게하고 있는가?

** [표창장은 필요로 amiright를?]

http://jhusain.github.io/learnrx/

https://github.com/timoxley/functional-javascript-workshop

https://medium.com/javascript-scene/the-two-pillars-of-javascript-ee6f3281e7f3

존 레식은 팬이 될 것 같다 - 나는 범위를 편집 할 수 있습니다>http://ejohn.org/blog/partial-functions-in-javascript/

나는이 게시물은 매우 빠르게 매우 일반적으로 매우 구체적인에서 갔다 실현 http://shop.oreilly.com/product/0636920028857.do

하고, 제안 된 경우 새 게시물을 만드십시오.

EDIT : 그룹에 lodash 및 밑줄에 대한 테스트를 추가했습니다. Lodash는 초당 약 870 ops로 초당 475 ops로 밑줄을 긋습니다. 테스트 here.

fast.js와 for 루프 및 js 네이티브 함수 here의 벤치 마크를 발견했으며 간단한 for 루프로 비슷하게 날아갔습니다.

+6

내장 매크로 기능이 너무 많이가 느린 그렇게. 일반적으로 실제로는 큰 문제는 아니지만 추상화는 그대로 유지하면서 [fast.js] (https://github.com/codemix/fast.js/tree/master)와 같은 것으로 대체 할 수 있습니다. – elclanrs

+0

elclanrs : 아, FastJS 및 LoDash에 대한 테스트를 추가해야합니다. 이러한 옵션을 완전히 잊어 버렸습니다. :) –

+0

흠. 나는 길이에 대해 cach'ing을 추가하여 모든 반복에 대한 히트가 없으며, 캐시를 사용하지 않는 것보다 실제로 느리다. 그래서 나에게 결과는 신뢰할 수 없다. 어떻게 캐싱이 캐싱보다 더 빠를 수 없습니까? btw - 나를 위해, "firefox"- 네이티브 브라우저 func는 라이브러리보다 훨씬 빠릅니다. –

답변

0

배열 방법은 각 반복의 기능 범위를 재 구축 할 필요, 2) 이들 (.map, .reduce)가 일부 (그래서 더 많은 메모리 어레이의 카피를 재 구축) 한 사람 루프보다 본질적으로 더 느리다 , 더 많은 GarbageCollection 및 일반적으로 더 많은 작업). 따라서 속도가 걱정된다면 가능한 한 낮게하십시오.

특히 알고리즘에는 런타임을 향상시키기 위해 할 수있는 몇 가지 사항이 있습니다. 가장 비싼 작업은 LevenshteinDistance이므로이를 최적화하면 속도가 상당히 향상됩니다.

당신이 할 수있는 가장 쉬운 방법은 문자열의 길이 검사를 수행하고 조기 반환을하는 것입니다 : 두 문자열의 길이가 options.distance 이상 차이가 나는 경우 Levenshtein 거리가 적어도 그 이상이된다는 것을 알고 있습니다. 그래서 당신은 쉽게 조기 복귀를 할 수 있습니다

for (var j = 0; j < compareArr.length; j++) { 
    // This check was added 
    if (Math.abs(res[i].name.length - compareArr[j].name.length) > options.distance) { 
     continue; 
    } 
    if(natural.LevenshteinDistance(res[i].name, compareArr[j].name) === options.distance) { 
     tempObj.matches.push(compareArr[j]) 
    } 
} 

더 나은 또 다른 유래 포스트에서 설명하는 방법 자체에 대한 몇 가지 개선 사항도 있습니다 : https://stackoverflow.com/a/3183199/574576