>웹 프론트엔드 >JS 튜토리얼 >Stream in Node에 대한 심층 분석

Stream in Node에 대한 심층 분석

青灯夜游
青灯夜游앞으로
2023-01-29 19:46:302896검색

플로우란 무엇인가요? 흐름을 이해하는 방법? 다음 기사는 Nodejs의 스트림에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다.

Stream in Node에 대한 심층 분석

stream은 EventEmitter를 상속받은 추상 데이터 인터페이스입니다. 데이터를 보내고 받을 수 있습니다. 그 본질은 아래와 같이 데이터 흐름을 만드는 것입니다. Stream in Node에 대한 심층 분석

Stream은 Node에서 고유한 개념이 아니라 운영 체제입니다. Linux |에서 가장 기본적인 동작 방식은 Stream인데 Node 레벨에서 캡슐화되어 해당 API를 제공합니다

왜 비트 단위로 해야 할까요?

먼저 다음 코드를 사용하여 약 400MB 정도의 파일을 생성합니다. [관련 튜토리얼 권장 사항: nodejs video tutorial]

Untitled 1.png

readFile을 사용하여 읽을 때 다음 코드

Untitled 2.png

가 정상입니다. 시작할 때 이 서비스는 약 10MB의 메모리를 차지합니다

Untitled 3.png

curl http://127.0.0.1:8000을 사용하여 요청을 시작하면 메모리는 약 420MB가 됩니다. curl http://127.0.0.1:8000发起请求时,内存变为了 420MB 左右,和我们创建的文件大小差不多

Untitled 4.png

改为使用使用 stream 的写法,代码如下

Untitled 5.png

再次发起请求时,发现内存只占用了 35MB 左右,相比 readFile 大幅减少

Untitled 6.png

如果我们不采用流的模式,等待大文件加载完成在操作,会有如下的问题:

  • 内存暂用过多,导致系统崩溃
  • CPU 运算速度有限制,且服务于多个程序,大文件加载过大且时间久

总结来说就是,一次性读取大文件,内存和网络都吃不消

如何才能一点一点?

我们读取文件的时候,可以采用读取完成之后在输出数据

Untitled 7.png

上述说到 stream 继承了 EventEmitter 可以是实现监听数据。首先将读取数据改为流式读取,使用 on("data", ()⇒{}) 接收数据,最后通过 on("end", ()⇒{}) 最后的结果

Untitled 8.png

有数据传递过来的时候就会触发 data 事件,接收这段数据做处理,最后等待所有的数据全部传递完成之后触发 end 事件。

数据的流转过程

数据从哪里来—source

数据是从一个地方流向另一个地方,先看看数据的来源。

  • http 请求,请求接口来的数据

    Untitled 9.png

  • console 控制台,标准输入 stdin

    Untitled 10.png

  • file 文件,读取文件内容,例如上面的例子

连接的管道—pipe

在 source 和 dest 中有一个连接的管道 pipe,基本语法为 source.pipe(dest)제목 없음 4.png

Change 스트림 쓰기를 사용하기 위한 코드는 다음과 같습니다

Untitled 5.png

요청을 다시 시작해보니 메모리가 약 35MB 정도만 차지하는 것을 발견했는데, 이는 readFile

Untitled 6.png스트리밍 모드를 사용하지 않고 작동하기 전에 대용량 파일이 로드될 때까지 기다리면 다음과 같은 문제가 발생합니다:

    일시적으로 너무 많은 메모리가 사용되어 시스템이 충돌합니다

    CPU 작동 속도가 제한되어 여러 서비스를 제공합니다. 대용량 파일은 용량이 너무 크고 로딩 시간도 오래 걸립니다
    요약하자면 대용량 파일을 한 번에 읽는 것은 메모리와 네트워크 모두에 부담이 됩니다
  • 어떻게 하면 조금씩 할 수 있나요?

    Untitled 11.png파일을 읽을 때 읽기가 완료된 후 데이터를 출력할 수 있습니다

    🎜Untitled 7.png🎜🎜위에서 언급했듯이 스트림은 EventEmitter를 상속하여 모니터링 데이터를 구현합니다. 먼저 읽기 데이터를 스트리밍 읽기로 변경하고 on("data", ()⇒{})를 사용하여 데이터를 수신하고 마지막으로 on("end", ()⇒를 사용합니다. { }) 최종 결과🎜🎜제목 없음 8.png 🎜🎜데이터가 전송되면 데이터 이벤트가 발생하고, 처리를 위해 데이터를 수신하며, 데이터가 모두 전송된 후 종료 이벤트가 발생합니다. 🎜

    🎜데이터 흐름 프로세스🎜🎜

    🎜데이터는 어디서 오는가?—source🎜🎜🎜데이터는 한 곳에서 다른 곳으로 흐릅니다. , 데이터 소스를 살펴보겠습니다. 🎜🎜🎜🎜http 요청, 인터페이스에서 데이터 요청🎜🎜제목 없음 9 .png🎜

  • 🎜🎜콘솔 콘솔, 표준 입력 stdin🎜🎜Untitled 10.png🎜🎜🎜파일 파일, 위의 예와 같은 파일 내용 읽기🎜

🎜연결된 파이프—pipe🎜🎜🎜소스와 대상에 연결된 파이프 파이프가 있습니다. 기본 구문은 source.pipe(dest), Source입니다. 및 dest는 파이프를 통해 연결되므로 데이터가 소스에서 대상으로 흐를 수 있습니다.🎜🎜위 코드처럼 데이터/종료 이벤트를 수동으로 모니터링할 필요가 없습니다.🎜🎜파이프를 사용할 때는 소스를 읽을 수 있어야 한다는 엄격한 요구 사항이 있습니다. 스트림, 그리고 대상은 쓰기 가능한 스트림입니다🎜🎜 정확히 흐르는 데이터가 무엇인가요? 코드에서 청크란 무엇입니까? 🎜🎜🎜갈 곳—dest🎜🎜🎜stream 세 가지 일반적인 출력 방법🎜🎜🎜🎜콘솔 콘솔, 표준 출력 stdout🎜🎜🎜🎜

  • http 요청, 인터페이스 요청의 응답

    Untitled 12.png

  • 파일 파일, 쓰기 파일

    Untitled 13.png

  • 스트림 유형

    Untitled 14.png

    읽기 가능 읽기 가능한 스트림

    읽을 수 있는 스트림은 데이터를 제공하는 소스의 추상화

    모든 Readables는 stream.Readable 클래스에 의해 정의된 인터페이스를 구현합니다

    Untitled 15.png

    ?

    Readable 스트림에는 청크 데이터의 흐름 모드를 결정하는

    flowing 모드

    Untitled 16.pngpause 모드

    의 두 가지 모드가 있습니다. 자동 흐름과 수동 흐름 Flow

    ReadableStream에는 flow 속성이 있는 _readableState 속성이 있습니다. 흐름 모드를 결정하기 위해 세 가지 상태 값이 있습니다.

    ture: 흐름 모드를 나타냅니다. false: 일시 중지 모드를 나타냅니다. null: 초기 상태

    • 온수기 모델을 사용하여 시뮬레이션할 수 있습니다. 데이터의 흐름. 온수탱크(버퍼 캐시 영역)에는 온수가 저장되어 있습니다(필수 데이터). 수도꼭지를 열면 온수가 계속 물탱크 밖으로 흘러나오고, 수돗물도 계속 물탱크로 흘러 들어가게 됩니다. 흐름 모드. 수도꼭지를 끄면 물탱크는 물 유입을 일시 중지하고 수도꼭지는 물 배출을 일시 중지합니다. 이것이 일시 정지 모드입니다.
    • Flow 모드

    데이터는 하위 레이어에서 자동으로 읽어와 흐름 현상을 형성하고 이벤트를 통해 애플리케이션에 제공됩니다. Untitled 17.png

    데이터 이벤트를 수신하여 이 모드로 들어갈 수 있습니다.
    데이터 이벤트가 추가될 때 쓰기 가능한 스트림에 데이터가 있으면 해당 데이터가 이벤트 콜백 함수로 푸시됩니다. 데이터 블록을 소비해야 합니다. 처리되지 않으면 데이터가 손실됩니다

    stream.pipe 메서드를 호출하여 Writeable에 데이터를 보냅니다

    • stream.resume 메서드 호출

    • 일시 중지 모드

      데이터는 내부 버퍼에 축적되며 표시되어야 합니다. 데이터 블록을 읽으려면 stream.read()를 호출하세요Untitled 18.png

    읽기 가능한 이벤트 듣기 쓰기 가능한 스트림은 데이터가 준비된 후 이 이벤트 콜백을 트리거합니다. 이때 데이터를 적극적으로 소비하려면 콜백 함수에서 stream.read()를 사용해야 합니다. 읽을 수 있는 이벤트는 스트림에 새로운 역학이 있음을 나타냅니다. 새 데이터가 있거나 스트림이 모든 데이터를 읽었거나

      두 모드 간 변환 방법
    • 읽기 가능한 스트림이 초기 상태에 있습니다. //TODO: 온라인 공유와 일치하지 않음Untitled 19.png

    일시 중지 모드를 흐름 모드로 전환
    - 监听 data 事件
    - 调用 stream.resume 方法
    - 调用 stream.pipe 方法将数据发送到 Writable
    • 흐름 모드를 일시 중지 모드로 전환
    • - 移除 data 事件
      - 调用 stream.pause 方法
      - 调用 stream.unpipe 移除管道目标

      Untitled 20.png구현 원칙

    • 읽을 수 있는 스트림 만들기 언제, Readable 객체를 상속하고 _read 메소드를 구현해야 합니다.

    사용자 정의 읽기 가능한 스트림을 생성하려면

    read 메소드를 호출할 때 전체 프로세스는 다음과 같습니다.

    Untitled 21.png

    doRead

    Untitled 22.png A 캐시는 스트림에 유지됩니다. 읽기 메소드가 호출되면 하위 레이어에서 데이터를 요청해야 하는지 판단됩니다

    버퍼 길이가 highWaterMark 값보다 0 이하이면 _read가 호출되어 하위 레이어에서 데이터를 가져옵니다소스 코드 링크

    Untitled 24.png

    Writable StreamWritable Stream

    Writable 스트림은 데이터 쓰기 대상의 추상화는 업스트림에서 흐르는 데이터를 소비하고 쓰기 가능한 스트림을 통해 데이터를 장치에 쓰는 데 사용됩니다. 일반적인 쓰기 스트림은 로컬 디스크에 쓰는 것입니다

    Untitled 25.png

    쓰기 가능한 스트림의 특징

    • write를 통해 데이터 쓰기

      Untitled 26.png

    • end를 통해 데이터를 쓰고 스트림을 닫습니다. end = write + close

      Untitled 27.pngUntitled 28.png

    • 기록된 데이터가 highWaterMark 크기에 도달하면 Drain이 실행됩니다. 이벤트

      Untitled 29.png

      는 ws.write(chunk)를 호출하고 false를 반환하여 현재 버퍼 데이터가 highWaterMark 값보다 크거나 같고 배수 이벤트가 트리거됨을 나타냅니다. 실제로 이는 경고 역할을 하지만 처리되지 않은 데이터는 항상 쓰기 가능한 스트림의 내부 버퍼에 백로그됩니다. 백로그가 Node.js 버퍼로 가득 찰 때까지는 강제되지 않습니다. .Interrupt

    사용자 정의 쓰기 가능 스트림

    모든 쓰기 가능 항목은 stream.Writeable 클래스에 의해 정의된 인터페이스를 구현합니다.

    하단 레이어에 데이터를 쓰려면 _write 메소드만 구현하면 됩니다

    Untitled 30.png

    • 호출 스트림에 데이터를 쓰기 위해 writable.write 메서드를 호출하면 _write 메서드를 호출하여 아래쪽 레이어에 데이터를 씁니다
    • _write 데이터가 성공하면 다음 데이터를 처리하기 위해 다음 메서드를 호출해야 합니다
    • 반드시 쓰기 가능한 스트림을 종료하려면 writable.end(data)를 호출하세요. 데이터는 선택 사항입니다. 그 후에는 새 데이터를 추가하기 위해 쓰기를 호출할 수 없습니다. 그렇지 않으면 오류가 보고됩니다.
    • end 메소드가 호출된 후 모든 기본 쓰기 작업이 완료되면 종료 이벤트가 트리거됩니다

    이중 스트림

    읽기 및 쓰기가 모두 가능한 이중 스트림. 실제로 Readable 및 Writable을 상속하는 스트림입니다. 읽기 가능한 스트림과 쓰기 가능한 스트림으로 모두 사용할 수 있습니다. 사용자 정의 이중 스트림은 Readable의 _read 메소드와 Writable의 _write 메소드를 구현해야 합니다.

    net 모듈은 소켓을 만드는 데 사용할 수 있습니다. 소켓은 NodeJS의 일반적인 이중입니다.

    Untitled 31.png

    클라이언트는 메시지를 보내는 데 사용됩니다. 읽기 스트림은 서버 메시지를 수신하는 데 사용됩니다. 두 스트림의 데이터 사이에는 직접적인 관계가 없습니다

    Untitled 32.png

    변환 스트림

    위 예에서 읽기 가능한 스트림(0/1)의 데이터와 쓰기 가능한 스트림 데이터('F', 'B', 'B')는 격리되어 있으며 둘 사이에는 관계가 없습니다. 그러나 Transform의 경우 쓰기 가능한 끝에 작성된 데이터는 이후에 읽기 가능한 끝에 자동으로 추가됩니다. 변환. Transform은 Duplex에서 상속되며 이미 _write 및 _read 메서드를 구현했습니다. _tranform 메서드만 구현하면 됩니다.

    gulp는 Stream 기반 자동화 구성 도구입니다. 공식에서 샘플 코드를 살펴보세요. website

    Untitled 33.png

    less → less로 CSS로 변환 → CSS 압축 수행 → 압축된 CSS

    Untitled 34.png사실 less()와 minifyCss()는 모두 입력 데이터에 대해 일부 처리를 한 다음 출력 데이터를 넘겨줍니다

    양면 및 변형 옵션

    위의 예와 비교하면 스트림이 생산자와 소비자 모두에게 서비스를 제공하는 경우 Duplex를 선택하게 됩니다. 데이터에 대한 일부 변환 작업만 수행할 경우 Transform

    배압 문제

    를 사용하도록 선택하게 됩니다.

    배압이란 무엇입니까

    배압 문제는 생산자-소비자 모델에서 발생합니다. 소비자 처리 속도가 너무 느립니다

    예를 들어 다운로드 프로세스 중 처리 속도는 3Mb/s이고 압축 중에는 처리 속도가 3Mb/s입니다. 프로세스가 너무 느립니다. 속도가 1Mb/s입니다. 이 경우 버퍼 큐가 곧 누적됩니다. 전체 프로세스의 메모리 소비가 증가하거나 전체 버퍼가 느려지고 일부 데이터가 손실됩니다. . 배압 처리란 무엇입니까?

    배압 처리는 위쪽으로 "울어내는" 과정으로 이해될 수 있습니다.

    압축 프로세스에서 버퍼 데이터 스퀴즈가 임계값을 초과한 것을 발견하면 다운로드 처리에 "울어줄" 것입니다. 너무 바빠서 더 이상 게시하지 마세요 Untitled 35.png

    메시지를 받은 후 다운로드 처리가 일시 중지되어 데이터 전송이 중단됩니다

    배압 처리 방법

    한 프로세스에서 다른 프로세스로 데이터를 전송하는 다양한 기능이 있습니다. Node.js에는 .pipe()라는 내장 함수가 있으며 궁극적으로 이 프로세스의 기본 수준에는 두 가지 관련 없는 구성 요소가 있습니다: 데이터 소스와 소비자

    .pipe()가 소스에서 호출하면 전송할 데이터가 있음을 소비자에게 알립니다. 파이프라인 기능은 이벤트 트리거에 적합한 백로그 패키지를 설정합니다Untitled 36.png

    데이터 캐시가 highWaterMark를 초과하거나 쓰기 대기열이 사용 중이면 .write()가 false를 반환합니다

    false가 반환되면 백로그 시스템이 개입합니다. 데이터를 전송하는 모든 데이터 스트림에서 들어오는 읽기 가능 항목을 일시 중지합니다. 데이터 스트림이 비워지면 배수 이벤트가 트리거되고 들어오는 데이터 스트림이 소비됩니다. 대기열이 완전히 처리되면 백로그 메커니즘을 통해 데이터가 다시 전송될 수 있습니다. 사용 중인 메모리 공간은 자체적으로 해제되고 다음 데이터 배치를 수신할 준비를 합니다

    파이프의 배압 처리를 볼 수 있습니다.

    데이터를 청크별로 나누고

    청크가 통과하면 씁니다. 큐가 너무 크거나 사용량이 많으면 읽기가 일시 중지됩니다

    큐가 비어 있으면 데이터를 계속 읽으세요

    Untitled 37.png

    노드 관련 지식을 더 보려면

    nodejs 튜토리얼

    을 방문하세요!

      위 내용은 Stream in Node에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

      성명:
      이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제