유니버스의 벤치마킹 읽기

내 노드 선택 유니버스 라이브러리를 사용할 계획이 있지만 전체 파일을 읽는 것이 상당히 비용이 많이 드는 작업이라는 점이 부담스럽습니다. 단일 레코드를 읽는 것은 느리지만 처리할 수 있습니다. 그러나 100k 항목의 파일을 선택하고 모든 항목을 읽는 것은 느립니다.

한 가지 해결책은 자바스크립트가 아닌 C로 모든 읽기를 수행하는 것이라고 생각하지만 최적화를 시작하기 전에 유효성을 검사하는 것이 좋습니다.

따라서 첫 번째 단계는 BASIC이 얼마나 빠른지 확인하는 것입니다. 이것이 가장 빠른 옵션일 것입니다.

기본 테스트



내가 실행할 테스트는 각각 200개의 필드가 있는 약 95,000개의 레코드가 있는 파일을 선택하는 것입니다. 하지만 그 중 150개만 지속적으로 채워집니다.

      OPEN '','INVENTORY-FILE' TO INVENTORY.FILE ELSE
         PRINT 'Unable to open file: INVENTORY-FILE - Press RETURN':
         INPUT ANYTHING
         STOP
      END
*
      BUFFER = ''
*
      SELECT INVENTORY.FILE
*
      LOOP
         READNEXT ITEM.ID ELSE ITEM.ID = ''
      UNTIL ITEM.ID = '' DO
         READ INVENTORY.ITEM FROM INVENTORY.FILE, ITEM.ID ELSE INVENTORY.ITEM = ''
         BUFFER<-1> = LOWER(INVENTORY.ITEM)
      REPEAT
*
      PRINT 'Items: ' : DCOUNT(BUFFER, @AM)


이것은 매우 간단한 프로그램입니다. 인벤토리 파일을 열고 선택한 다음 모든 레코드를 버퍼로 읽어 들입니다.

시간이 얼마나 걸리는지 확인하기 위해 Linux 명령줄에서 시간을 몇 번 사용하고 대충 추측해 보겠습니다.

> time uv "RUN BP TEST.READS"


이는 다음과 같은 일반적인 결과를 제공합니다.

bash-4.2$ time uv "RUN BP TEST.READS"
Items: 94872

real    0m0.522s
user    0m0.285s
sys     0m0.241s
bash-4.2$ time uv "RUN BP TEST.READS"
Items: 94872

real    0m0.510s
user    0m0.284s
sys     0m0.230s


여기서 놀라운 점은 READ 문을 MATREAD로 변경하면 프로그램 실행 시간이 길어진다는 것입니다. 배열의 크기를 지정하는 것이 더 빠를 것이라고 생각했지만 실제로는 더 길어집니다.

배열의 크기를 지정하는 것은 실제로 200개의 변수를 선언하고 레코드를 읽는 것은 각 필드를 변수 중 하나에 할당하는 것과 관련되기 때문일 수 있습니다. 대, 내가 가정하는 READ를 사용하면 필드에 대해 인덱싱된 메모리의 큰 청크 1개를 사용합니다.

MATREAD는 약 1.2초 내에 실행되는 반면 READ는 0.52초 내에 실행됩니다. 매우 흥미롭고 이 성능 테스트를 실행하게 되어 이미 기쁩니다.

부록

전체 데이터를 버퍼에 추가하는 것보다 특정 값을 버퍼로 읽는 데 시간이 더 걸렸습니다. 일리가 있는 일이지만 무슨 일이 일어나고 있는지 궁금합니다. 비용이 그렇게 많이 들 줄은 몰랐는데 처음 2개 값만 읽어도 터무니없이 비쌌습니다. 한 가지 이유는 유니버스가 문자열 구문 분석을 사용하여 값을 가져오기 때문일 수 있습니다. 읽기를 수행하고 있기 때문에 개별 값을 얻는 데 훨씬 더 빠르지만 변수를 설정하는 비용이 있는 MATREAD와 비교하여 각 항목을 구문 분석해야 할 수 있습니다.

이것은 READ가 데이터를 빨리 가져오는 데는 좋지만 처리하기 어려운 반면 MATREAD는 데이터를 가져오는 데 느리지만 처리하는 데 빠르다는 재미있는 작은 점입니다.

이제 제가 할 수 있는 최선의 가정은 이 BASIC 프로그램입니다. 노드 버전은 확실히 더 오래 걸립니다.

테스트 노드



노드 버전에는 몇 가지 눈에 띄는 문제가 있습니다. 첫 번째는 읽을 때마다 javascript에서 C로 넘어가는 것입니다. 이것은 비싸야 합니다. 다음 문제는 각 읽기가 RPC 포트를 거쳐야 한다는 것입니다. localhost에서는 괜찮을 수 있지만 멀리 떨어진 서버에서는 네트워크 시간이 킬러가 됩니다.

const mv = require("pick-mv");
const Universe = require('pick-universe');

const uv = new Universe("localhost", "user", "password", "/path/to/account");

uv.StartSession();

const INV = uv.Open("INVENTORY-FILE");
uv.Select(INV);

let buffer = [];

while (true) {
    let id = uv.ReadNext();
    if (id === null) break;
    let record = uv.Read(id, INV);
    buffer.push(record);
}

uv.EndAllSessions();

console.log(`Items: ${buffer.length}`);


BASIC과 노드 버전이 거의 동일하고 라인 수가 같은 범위에 있다는 점이 마음에 듭니다.

성능 테스트는 localhost에서 진행됩니다.

bash-4.2$ time node test.js
Items: 94873

real    0m7.528s
user    0m1.610s
sys     0m2.391s
bash-4.2$


확실히 더 깁니다! 15배 더 길다. 이것은 또한 네트워크를 통해 크게 올라갑니다. 나는 거의 15분을 기다렸지만 테스트를 종료했을 때 여전히 끝나지 않았습니다.
이것은 기본적으로 네트워크에서 노드 라이브러리를 사용하는 것이 의미가 없으며 작업을 수행하고 데이터를 반환하기 위해 서버에서 서브루틴을 호출하는 것이 더 낫다는 것을 의미합니다.

우리가 할 수 있는 변화는 readlist를 사용하여 한 번에 모든 ID를 읽는 것입니다. 이제 레코드 읽기를 위해 C로 돌아가기만 하면 되므로 속도가 빨라집니다.

const mv = require("pick-mv");
const Universe = require('./index');

const uv = new Universe("localhost", "user", "password", "/path/to/account");

uv.StartSession();

const INV = uv.Open("INVENTORY-FILE");
uv.Select(INV);

let buffer = [];

let ids = mv.MVToArray(uv.ReadList());

for (let id of ids) {
    let record = uv.Read(id, INV);
    buffer.push(record);
}

uv.EndAllSessions();

console.log(`Items: ${buffer.length}`);


소요 시간:

bash-4.2$ time node  test.js
Items: 94873

real    0m4.818s
user    0m1.267s
sys     0m1.331s


이것은 우리가 javascript에서 readnexts를 수행할 때 얻은 7.5초보다 약간 낫지만 여전히 상당히 느립니다.

이제 증거가 있으므로 C에 머물면서 레코드 목록을 배열로 읽은 다음 해당 배열을 노드로 반환하는 ReadAll 함수를 작성하려고 합니다. 이것은 여전히 ​​네트워크 호출을 수행하므로 Universe 서버가 localhost에서 실행되고 있는지 확인하는 더 깊은 문제를 해결할 것이라고 생각하지 않습니다.

좋은 웹페이지 즐겨찾기