Larry Lawless Larry Lawless - 15 days ago 10
HTTP Question

Why does PHP come out on top over Node.js when I benchmark them on a IO operation?

I'm running an benchmark with the apache benchmarking tool on PHP and Node.js, port 80 and port 8000 respectively. Node benchmark command below, swapping out the port when running tests on PHP:

ab -n 100 -c 100 http://localhost:8000/


What I'm doing in the programs is simply reading in a 10MB text file and then send that back to the client. To my surprise the PHP benchmark takes around 6 seconds and Node.js is way up at 13 seconds.

This is the text file:

https://github.com/jamesward/play-load-tests/blob/master/public/10mb.txt

This is the code for each:

Node.js

var http = require("http");
var fs = require("fs");
var s = http.createServer(function(req, res) {

res.writeHead(200, {"content-type": "text/plain"});

fs.readFile("./10mb.txt", "utf8", function(err, data) {

res.end(data);

});


});

s.listen(8000);





PHP

<?php

echo file_get_contents("./10mb.txt");





Am I doing something wrong in the Node code? Otherwise I'm pretty confused, one of the main selling points of Node was that it was fast in OI operations. What point am I missing?

Answer

PHP will run multithreaded so some of the 100 requests will be in parallel.

Node.js is singlethreaded but asynchronous. Generally this trade-off is a win for Node.js since it will consume less RAM and incurs fewer context switches. In this case however you're reading a huge chunk of data (10mb) into RAM and then sending that out.

Memory operations in node.js are synchronous. So while both the file read and socket write operations are asychronous there is a huge memcpy in there that effectively blocks the interpreter.

The correct way to handle very large data in node.js is to use streams:

var s = http.createServer(function(req, res) {
    var readStream = fs.createReadStream("./10mb.txt");

    res.writeHead(200, {"content-type": "text/plain"});

    readStream.pipe(res);
});
Comments