【问题标题】:Why is only one 'data' event emitted when stdout exceeds the buffer size?当标准输出超过缓冲区大小时,为什么只发出一个“数据”事件?
【发布时间】:2020-08-27 05:58:30
【问题描述】:

背景:https://github.com/Almenon/AREPL-vscode/pull/332 (很多,建议先往下看)

我假设节点在达到highWaterMark 时刷新标准输出。它是否正确?根据这个stackoveflow,答案似乎是肯定的。假设是这样,如果超过了高水位线,额外的字符应该会出现第二次刷新,对吧?

无论缓冲区大小如何,节点似乎都忽略了高水位标记并且仅刷新一次。

用预期/实际结果重现我的问题的示例代码:

import { spawn } from "child_process"

// 8192*2 (16384 aka 16KB) is the highWaterMark (aka buffer size?)
const node_process = spawn("node", ["-e", "process.stdout.write('a'.repeat(8192*2+1));setTimeout(()=>{console.log('done')},4000)"])

node_process.on('error', err => console.error(err))

let numFlushes = 0
node_process.stdout.on('data', (buffer: Buffer) => {
    numFlushes += 1
    const str = buffer.toString()
    console.log(`flush number: ${numFlushes}\
    Buffer length: ${buffer.length}`)
    if (buffer.length < 20) console.log(str)
})

/*
Expected result: 3 flushes, one when highWaterMark is reached, another with rest of stdout, final with done log
Acutal result: 2 flushes. All of stdout is recieved at once. 4 seconds later comes the done log.
Related docs: https://nodejs.org/docs/latest-v12.x/api/stream.html#stream_buffering
OUTPUT (courtesy of quokka)
flush number: 1    Buffer length: 16385
  at ​​​`flush number: ${ numFlushes }\ Buff...​​​ ​personal/test_node_buffer.ts:11:4
flush number: 2    Buffer length: 11
  at ​​​`flush number: ${ numFlushes }\ Buff...​​​ ​personal/test_node_buffer.ts:11:4
done
  at ​​​str​​​ ​personal/test_node_buffer.ts:13:8
*/

https://gist.github.com/Almenon/6286ca1baf0714b56dc133e03728eb12

我一直在 Windows 10 上对此进行测试。 在 linux 上,如果您执行 *8+2,它会按预期进行 3 次刷新。奇怪的。 除此之外,两个平台的行为相同。

https://repl.it/@almenon/testBufferSize

【问题讨论】:

  • process.stdout.write() 这么大,您可能在 .write() 中触发了错误。您需要在process.stdout 上安装error 事件的侦听器或使用.write() 的回调来查看。对于任意大的写入,流没有无限缓冲能力。他们可能会在某处划清界限。
  • 另外,理解您的问题所需的代码应粘贴到问题本身中。像您一样提供更多支持代码或完整实现的链接是很好的,但出于各种原因,应将查看主要问题所需的代码直接粘贴到您的问题中。这是因为外部链接有随时间中断或变化的习惯,使问题无法作为长期参考。将代码粘贴到问题中还可以将其编入索引以供移动用户更有效地搜索和查看。
  • @jfriend00 我尝试为错误事件添加侦听器,但没有看到任何错误。我还将代码移到问题本身中。
  • 当我运行您的代码并进行更多调试时,没有错误。所有的输出都同时出现。当我单步执行process.stdout.write() 时,它只会写入全部数量而根本没有缓冲。 highWaterMark用于判断.write()是否会返回false,表示在drain事件发生之前不能再做writes(),但不用于使其分为两次写入。跨度>
  • 嘿,可能是系统命令行缓冲区的问题?检查这个:const node_process = spawn("stdbuf", ["-o", "0", "node" "-e", "process.stdout.write('a'.repeat(8192*2+1));setTimeout(()=&gt;{console.log('done')},4000)"])

标签: node.js sockets stream buffer stdout


【解决方案1】:

https://github.com/nodejs/node/issues/33465

Node 在“感觉像它的时候”发出数据事件

是的,这是认真的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-25
    • 2018-12-12
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    • 2014-10-07
    • 2012-06-09
    • 2011-01-05
    相关资源
    最近更新 更多