我正在对一个Java UDP客户端进行基准测试,它连续发送100字节的数据报,速度尽可能快。它是使用java.nio.*
实现的。测试表明,它能够实现稳定的吞吐量为每秒220k个数据报。我没有使用服务器进行测试;客户端只是将数据报发送到localhost上的某个未使用的端口。
我决定在Node.js中运行相同的测试,以比较这两种技术,但令人惊讶的是,Node.js的性能比Java慢10倍。让我带你走一遍我的代码。
首先,我使用Node.js的dgram模块创建了一个UDP套接字:
var client = require('dgram').createSocket("udp4");
然后我创建一个函数,使用该套接字发送数据报:
function sendOne() {
client.send(message, 0, message.length, SERVER_PORT, SERVER_ADDRESS, onSend);
}
变量
message
是应用程序启动时从一个包含一百个字符的字符串创建的缓冲区:var message = new Buffer(/* string with 100 chars */);
函数
onSend
仅增加一个变量,该变量保存到目前为止发送的数据报数量。接下来,我有一个使用setImmediate()
不断调用sendOne()
的函数。function sendForever() {
sendOne();
setImmediate(sendForever);
}
起初我尝试使用process.nextTick(sendForever)
,但是我发现它总是将自己放在事件队列的顶部,甚至在IO事件之前,正如文档says:
它在事件循环的后续刻度中,在任何其他I/O事件(包括计时器)触发之前运行。
这会防止发送IO事件的发生,因为nextTick
不断将sendForever
放在每个刻度的队列顶部。队列随着未读IO事件而增长,直到使Node.js崩溃:
fish: Job 1, 'node client' terminated by signal SIGSEGV (Address boundary error)
另一方面,
setImmediate
在 I/O 事件回调之后触发,这就是我使用它的原因。我还创建了一个定时器,每秒钟打印一次控制台,显示上一秒发送了多少数据报:
setInterval(printStats, 1000);
最后,我开始发送:
sendForever();
在与Java测试运行相同的机器上,Node.js每秒稳定处理 21k个数据报,比Java慢十倍。
我最初的猜测是为了尝试使吞吐量加倍,在每个时刻放置两个
sendOne
:function sendForever() {
send();
send(); // second send
setImmediate(sendForever);
}
但这并没有改变吞吐量。
我在GitHub上有一个可用的仓库,其中包含完整的代码:
https://github.com/luciopaiva/udp-perf-js
只需将其克隆到您的计算机中,cd
进入该文件夹并运行:
node client
我希望能就如何在Node.js中改进此测试以及是否有办法提高Node.js的吞吐量开展讨论。有什么想法吗?
P.S.: 对于那些感兴趣的人,这里是Java部分。