流上的 .pipe 和管道有啥区别

Posted

技术标签:

【中文标题】流上的 .pipe 和管道有啥区别【英文标题】:What's the difference between .pipe and pipeline on streams流上的 .pipe 和管道有什么区别 【发布时间】:2020-03-11 12:37:28 【问题描述】:

我在 node.js 中找到了两种不同的管道流方式

众所周知的.pipe()流方法

https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options

流的独立功能

https://nodejs.org/api/stream.html#stream_stream_pipeline_streams_callback

我应该使用哪一个,这两者之间有什么好处?

【问题讨论】:

【参考方案1】:

TL;DR - 你最好使用pipeline

什么是管道?

From the docs:一种模块方法,用于在流之间进行管道转发错误并正确清理,并在管道完成时提供回调。

使用管道的动机是什么?

❌ 我们来看看下面的代码:

const  createReadStream  = require('fs');
const  createServer  = require('http');
const server = createServer(
  (req, res) => 
    createReadStream(__filename).pipe(res);
  
);

server.listen(3000);

这里有什么问题? 如果响应将退出或客户端关闭连接 - 那么读取流未关闭或销毁,这会导致内存泄漏。

✅因此,如果您使用pipeline,它将关闭所有其他流并确保没有内存泄漏。

const  createReadStream  = require('fs');
const  createServer  = require('http');
const  pipeline  = require('stream');

const server = createServer(
  (req, res) => 
    pipeline(
      createReadStream(__filename),
      res,
      err => 
        if (err)
          console.error('Pipeline failed.', err);
        else
          console.log('Pipeline succeeded.');
      
    );
  
);

server.listen(3000);

【讨论】:

【参考方案2】:

根据文档,他们都做同样的事情。但也有一些不同:

.pipe()Readable 的方法,而pipelinestream 的模块方法,接受流到管道。 pipeline() 方法在管道完成时提供回调。 pipeline() 方法是从 node 10 版本开始添加的,而.pipe 从最早版本的 node 开始存在。

在我看来,pipeline() 的代码看起来更简洁一些,但你可以同时使用它们。

.pipe() 的示例:

const fs = require('fs');
const r = fs.createReadStream('file.txt');
const z = zlib.createGzip();
const w = fs.createWriteStream('file.txt.gz');
r.pipe(z).pipe(w);

pipeline() 的例子:

const  pipeline  = require('stream');
const fs = require('fs');
const zlib = require('zlib');

pipeline(
  fs.createReadStream('archive.tar'),
  zlib.createGzip(),
  fs.createWriteStream('archive.tar.gz'),
  (err) => 
    if (err) 
      console.error('Pipeline failed.', err);
     else 
      console.log('Pipeline succeeded.');
    
  
);

【讨论】:

【参考方案3】:

pipelinepipe 的改进版本,它自 Node.js v10 起被添加到流模块

此外,pipeline 接受任意数量的参数,最后一个参数是一个回调,用于了解管道何时结束或引发错误。

使用管道:

mySourceStream.pipe(myStream).pipe(anotherStream)

使用管道:

mySourceStream.pipeline(myStream, anotherStream, err => 
  if (err) 
    console.log('There is an error')
   else 
    console.log('pipeline successful')
  
)

【讨论】:

以上是关于流上的 .pipe 和管道有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

sklearn Pipeline 和 DataFrameMapper 有啥区别?

linux中的pipe和fifo的区别

linux中的pipe和fifo的区别

Windows中的命名管道,FILE_FLAG_OVERLAPPED和PIPE_NOWAIT之间的区别

消息队列和管道的区别

subprocess.call() 和 subprocess.Popen() 之间有啥区别使 PIPE 对前者的安全性降低?