병렬적으로 처리하기

nn·2023년 6월 27일
0

비동기 I/O

비동기 I/O는 싱글스레드 기반에서 하나의 스레드에서 CPU를 효율적으로 점유하는 방법이다.

자바스크립트는 싱글스레드이기 때문에 로직을 싱글스레드로만 제어할 뿐 병렬적인 처리도 필요하다.


 go([1, 2, 3, 4, 5],
    L.map(a => delay500(a * a)),
    L.filter(a => delay500(a % 2)),
    L.map(a => delay500(a * a)),
   	reduce(add)
    log
  )

위 코드는 순차적으로 1이 L.map, L.filter, L.map이 실행되고 reduce는 2가 L.map, L.filter, L.map가 실행될때까지 기다렸다가 연산하고 그 다음 3,4,,,가 인자로 들어가며 작동할 것이다.

reduce를 병렬적으로 처리하기위해 C.reduce를 만들어보자

  C.reduce = curry((f, acc, iter) => {
    if (iter) {
      return reduce(f, acc, [...iter])
    } else {
      return reduce(f, [...acc])
    }
  });

C.reduce 위의 map, filter가 모두 실행될 때까지 기다렸다가 이 모든 값을 펼쳐서 reduce를 한번에 실행한다.

L.map, L.filter는 C.reduce에 있는 전개연산자로 인해 프로미스들이 모두 즉시 평가된다.

전개 연산자가 없는 경우 next()가 발생할때마다 값을 하나씩 순차적으로 빼오지만 전개 연산자를 사용하는 경우 next()로 반환 될 값이 한꺼번에 담기게된다.
그러므로 동시적으로 모든 프로미스들이 동작하여 C.reduce프로미스가 처리된 값을 합산만 하여 병렬처리가 가능하게 된 것이다.


위 에러는 전개 연산자를 통해 map,filter가 작동하던 중 생긴 reject가 catch되면서 생긴 에러이다.

즉 로직의 작동결과에는 영향을 미치지 않지만 catch가 되어 불필요한 로그가 찍히고 있다.

reject이 있지만 catch를 하지 않고 넘기기 위해서 아래와 같이 할 수 있다.

중요한 점은 이미 catch가 되어 평가가 끝난 것이 아니라, catch를 걸어놓기만 상태를 유지하여 catch를 다음 시점에 넘겨서 평가 되도록 하는 것이다.

  C.reduce = curry((f, acc, iter) => {
    const iter2 = catchNoop(iter ? [...iter] : [...acc]);
    iter2.forEach(a => a.catch(function() {}))
    if (iter) {
      return reduce(f, acc, iter2)
    } else {
      return reduce(f, iter2)
    }
  });

이렇게 iter2에 reject가 있는 경우 catch에서 아무것도 하지 않도록 하면 에러가 뿜어지지 않게 된다.

profile
내가 될 거라고 했잖아

0개의 댓글