Node.js 集群;仅在使用颜色时混乱的控制台输出

Posted

技术标签:

【中文标题】Node.js 集群;仅在使用颜色时混乱的控制台输出【英文标题】:Node.js cluster; jumbled console output ONLY when using colour 【发布时间】:2019-03-09 02:23:10 【问题描述】:

你好!我正在运行一个包含多个节点的集群节点项目。他们做了相当多的控制台输出。我也希望能够做出漂亮的彩色输出。

我的问题:只有在使用颜色时,我才会出现混乱的、与比赛条件有关的控制台输出。

我一直在努力解决我的问题,我目前的设置是让集群中的每个节点都有自己唯一的字符串。这是节点将输出到控制台的唯一字符串。

let chars = 'abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let getMyUniqueString = () => 
  return chars[Math.floor(Math.random() * chars.length)].repeat(100);
;

我运行了一堆节点,它们使用这个函数来确定它们的唯一字符串,我看到如下内容:

是不是很漂亮!无论所有这些节点输出多长时间和多猛烈,此控制台输出都不会混乱。

现在,我尝试使用仅包含一点点颜色的独特字符串:

let chars = 'abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let getMyUniqueString = () => 
  let redEscSeq = '\x1b[41m';
  let clearEscSeq = '\x1b[0m';
  let aRedBoxOfText = redEscSeq + '  ' + clearEscSeq;
  let repeatedChars = chars[Math.floor(Math.random() * chars.length)].repeat(100);
  return aRedBoxOfText + repeatedChars;
;

看看我的一些结果看起来多么悲伤!

通过console.log 函数将数据跨所有节点发送到终端的唯一方式。

为什么console.log 在没有颜色的情况下足够聪明,可以让许多节点的输出保持整洁,但在包含一点颜色的情况下却不够聪明??

感谢您的帮助!

(仅供参考,下图是我希望在彩色情况下始终如一地看到的那种杂乱无章的输出;它只是每行前缀的一个红色框(两个带有红色背景色的空格):)

编辑:虽然此问题存在于本机 Windows“cmd.exe”控制台、powershell 控制台和 ConEmu(屏幕截图中显示的一个不错的第 3 方 Windows 终端)中,但 Cygwin 终端中不存在此问题!在 Cygwin 中从来没有任何混乱,即使有大量的颜色和异步输出。我能做些什么来鼓励其他控制台中的这种 Cygwin 行为吗?

【问题讨论】:

这可能是 windows/unix Unicode 问题还是 CRLF vs LF 之类的行尾问题? 另外根据wikiwindows 并不天真地支持ANSI 着色,也许你需要确保命令行使用的是windows 10 而不是legacy 【参考方案1】:

这是一个竞争条件,你不可能对它做任何事情,也许除了向 nodejs 使用的库报告一个错误。

虽然 Windows API 本身确实支持在单个 API 调用中打印多色字符串,如下所示:https://docs.microsoft.com/en-us/windows/console/writeconsoleoutput,其中每个字符都包含其颜色信息。但它也不支持 ANSI 转义码。而这并不是 javascript 实际使用的。

Nodejs 引擎使用一个名为 libuv 的库将字符串写入终端,这是跨平台的,并在内部翻译 ANSI 转义码以执行正确的操作。但是,如果您仔细查看用于处理 ANSI 转义码的source of libuv,您会发现它在每个转义码之后都会进行一次完整的缓冲区刷新,这意味着在某些时候它必须成为多个 Windows API 调用才能打印一行文本。

在正常情况下这显然不是问题,但如果你有多个线程在编写,这意味着这些行的一部分可能会变得混乱......就像你在这里看到的一样。

所以这里的答案是没有解决方案。或者您接受使用 cygwin 作为解决方案。

【讨论】:

我仍然有点困惑 cygwin 如何正确执行 - libuv 是否检测并适应 console.log 链接到的终端类型? libuv 在检测到 cygwin 是否正在使用控制台时是否会避免执行此缓冲区刷新?如果可以的话,请尽快告诉我,因为赏金即将到期,我希望能够提供! 您是否在 cygwin 上运行了特定于 cygwin 的 nodejs 版本?如果是这种情况,很可能是在 libuv 中使用了不存在该问题的 unix 特定代码。如果这得到确认,我将更新我的答案以包含它,并可能添加更多详细信息。 不能再编辑原始评论了,但即使你确实在cygwin上使用了普通版本的node,它也有可能从那里加载unix版本的libuv,在cygwin下编译。这也可以解释这个问题。也可以使用 WSL(用于 linux 的 windows 子系统)使其正常工作。 您应该能够通过从普通 Windows 终端运行 cygwin 的 bash 并从那里运行节点来确认该假设。如果问题没有出现在那里,很可能是使用 libuv 中的 unix 特定代码加载的。

以上是关于Node.js 集群;仅在使用颜色时混乱的控制台输出的主要内容,如果未能解决你的问题,请参考以下文章

由于这一行代码,控制台中的颜色混乱了

使用集群将 Socket.IO 扩展到多个 Node.js 进程时的一些问题

C/C++ 改变控制台输文字颜色:SetConsoleTextAttribute()

C/C++ 改变控制台输文字颜色:SetConsoleTextAttribute()

Node.js 集群共享缓存

Node.JS 内置集群还是 PM2 集群?