使用Node.js消费者会导致命名管道(fifo)吞吐量下降。

3

我试图使用命名管道将一系列图像从Python进程传递到Node.js进程,理想情况下每秒传输60帧,对于1兆字节的图像。但实际上,我只能获得每秒25帧的吞吐量。为了测试,我将帧从一个Python进程传输到第二个Python进程,我能够获得大约每秒500帧的传输速率。我是Node.js新手,所以很可能会漏掉某些东西,但我认为它应该具有相当的速度。为什么我的Node.js程序在从命名管道中读取数据时速度如此之慢?

我正在使用Node.js可读流,并在'readable'事件上进行读取:

reader.js

const fs = require('fs');

fifo = fs.createReadStream(process.argv[2], { highWaterMark: 4*1024**2, });

let t0 = Date.now();
fifo.on('readable', () => {
  const chunk = fifo.read(1024 ** 2);
  if (chunk !== null) {
    let t1 = Date.now();
    process.stdout.write(`${(t1 - t0)/1000.}s, ${1000./(t1 - t0)}fps\n`);
    t0 = t1;
  }

});

fifo.on('end', () => {
  process.stdout.write('end');
});

我的Python生产者将字节写入命名管道,就像写文件一样:

producer.py

import sys
import numpy as np

im = np.random.randint(0, 255, size=(1024, 1024)).astype(np.uint8).ravel()

with open(sys.argv[1], 'wb') as f:
    while True:
        f.write(im.tobytes())
        f.flush()

Python读取器会像读文件一样从命名管道中读取数据:

reader.py

import sys
import numpy as np
import time

l = 1024 ** 2
t0 = time.time()
with open(sys.argv[1], 'rb') as f:
    while True:
        im = f.read(l)
        t1 = time.time()
        print('{}s, {}fps'.format(t1 - t0, 1/(t1 - t0)))
        t0 = t1

测试Python到JavaScript的传输:

mkfifo /tmp/video; python producer.py /tmp/video & node reader.js /tmp/video

为了测试 Python 到 Python 的传输:

mkfifo /tmp/video; python producer.py /tmp/video & python reader.py /tmp/video

我正在使用Mac(OS 10.13.6,2.7 GHz英特尔Core i5)。Python 3.7.0。Node v8.9.1。
我还尝试使用nodejs读取器的"data"事件,但速度同样很慢。难道nodejs事件有足够的开销来减缓读取速度吗?
如有任何想法,将不胜感激!
1个回答

0

这似乎是macOS的限制。

据我所知,macOS上的命名管道具有固定的缓冲区大小,无法更改(大约为16或64K),而在Linux上,大小可调整至1M。

我进行了测试,发现Linux上reader.js的性能要好得多,与reader.py差不多。

快速测试表明,将Python进程作为子进程运行可以显著提高读取速度:

// reader.js
const { spawn } = require('child_process');
const fifo = spawn('python', ['producer.py']).stdout; // (instead of fs.createReadStream(...))
...

// producer.py
...
f = sys.stdout.buffer
while True:
    f.write(im.tobytes())
    f.flush()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接