└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Go vs Node.JS vs PHP + Iris vs Express vs Laravel 2 | 3 | We were arguing wheter to use PHP or go with Node.js for a project we are working on. It's practically a hybrid of the world's most popular online marketplace to list find and rent vacation homes and a popular social media network. We finally decided to go with Node.js after some benchmarks we made comparing PHP and Node.js and their most popular frameworks available. 4 | 5 | UPDATE: Added Go to the benchmark for future considerations 6 | 7 | 8 | 9 | #### Test machine: 10 | - MacBook Pro (13 inch, late 2012) 11 | - 2.9GHz Intel Core i7 12 | - RAM 16GB 1333MHz DDR3 13 | - HDD 1TB 14 | 15 | - Server: nginx/1.10.0 16 | 17 | - PHP 7.0.7 18 | - Laravel 5.3.0 19 | 20 | 21 | - Node 6.5.0 22 | - Express 4.13.4 23 | 24 | #### Test Condition #1 25 | - Duration: 5s 26 | - Threads: 10 27 | - Connections: 5000 28 | 29 | ```php 30 | Go 31 | wrk -d5s -t10 -c5000 http://localhost:8080 32 | 33 | Node.js 34 | wrk -d5s -t10 -c5000 http://localhost:3000 35 | 36 | Laravel 37 | wrk -d5s -t10 -c5000 http://laravel.dev 38 | ``` 39 | 40 | ```php 41 | Simple GET request that returns "Hello World" 42 | /** 43 | * Test results: 44 | * | Rank | Subject | Requests/sec | Data/sec | Avg. Response | 45 | * ------------------------------------------------------------------------------------- 46 | * | 1 | Iris(Go, Multi Thread) | 57,589.26 | 7.80MB | 3.88ms | 47 | * | 2 | Pure Go(Multi Thread) | 51,782.44 | 6.32MB | 4.34ms | 48 | * | 3 | Pure Node.js(Multi Thread) | 20,873.34 | 3.09MB | 11.40ms | 49 | * | 4 | Pure Node.js(Single Thread) | 10,375.05 | 1.53MB | 22.70ms | 50 | * | 5 | Express(JS, Multi Thread) | 3,426.94 | 779.76KB | 68.92ms | 51 | * | 6 | Pure PHP(Multi Thread) | 3,147.95 | 667.17KB | 23.28ms | 52 | * | 7 | Express(JS, Single Thread) | 2,386.69 | 543.06KB | 97.97ms | 53 | * | 8 | Laravel(PHP, Multi Thread) | 26.23 | 101.44KB | 392.64ms | 54 | * ------------------------------------------------------------------------------------- 55 | */ 56 | ``` 57 | 58 | ```php 59 | Simple GET request that returns prime numbers between 0 and 1000 60 | /** 61 | * Test results: 62 | * | Rank | Subject | Requests/sec | Data/sec | Avg. Response | 63 | * ------------------------------------------------------------------------------------- 64 | * | 1 | Pure Node.js(Multi Thread) | 14,290.14 | 10.75MB | 16.57ms | 65 | * | 2 | Pure Node.js(Single Thread) | 7,902.13 | 5.95MB | 19.13ms | 66 | * | 3 | Pure Go(Multi Thread) | 7,805.24 | 5.67MB | 30.42ms | 67 | * | 4 | Iris(Go, Multi Thread) | 6,646.82 | 4.96MB | 35.64ms | 68 | * | 5 | Express(JS, Multi Thread) | 3,534.16 | 2.95MB | 66.85ms | 69 | * | 6 | Pure PHP(Multi Thread) | 3,189.39 | 1.43MB | 29.21ms | 70 | * | 7 | Express(JS, Single Thread) | 2,206.12 | 1.84MB | 106.68ms | 71 | * | 8 | Laravel(PHP, Multi Thread) | 44.67 | 60.28KB | 370.60ms | 72 | * ------------------------------------------------------------------------------------- 73 | */ 74 | ``` 75 | 76 | #### Test Condition #2 77 | - Duration: 30s 78 | - Threads: 10 79 | - Connections: 5000 80 | 81 | ```php 82 | Go 83 | wrk -d30s -t10 -c5000 http://localhost:8080 84 | 85 | Node.js 86 | wrk -d30s -t10 -c5000 http://localhost:3000 87 | 88 | Laravel 89 | wrk -d30s -t10 -c5000 http://laravel.dev 90 | ``` 91 | 92 | ```php 93 | Simple GET request that returns "Hello World" 94 | /** 95 | * Test results: 96 | * | Rank | Subject | Requests/sec | Data/sec | Avg. Response | 97 | * ------------------------------------------------------------------------------------- 98 | * | 1 | Iris(Go, Multi Thread) | 56,757.36 | 7.69MB | 3.98ms | 99 | * | 2 | Pure Go(Multi Thread) | 47,001.13 | 5.74MB | 4.83ms | 100 | * | 3 | Pure Node.js(Multi Thread) | 24,559.01 | 3.63MB | 9.76ms | 101 | * | 4 | Pure Node.js(Single Thread) | 11,629.34 | 1.72MB | 20.63ms | 102 | * | 5 | Express(JS, Multi Thread) | 4,429.92 | 0.98MB | 54.23ms | 103 | * | 6 | Express(JS, Single Thread) | 2,689.57 | 611.98KB | 89.16ms | 104 | * | 7 | Pure PHP(Multi Thread) | 549.22 | 116.91KB | 27.73ms | 105 | * | 8 | Laravel(PHP, Multi Thread) | 35.35 | 226.28KB | 144.51ms | 106 | * ------------------------------------------------------------------------------------- 107 | */ 108 | ``` 109 | 110 | ```php 111 | Simple GET request that returns prime numbers between 0 and 1000 112 | /** 113 | * Test results: 114 | * | Rank | Subject | Requests/sec | Data/sec | Avg. Response | 115 | * ------------------------------------------------------------------------------------- 116 | * | 1 | Pure Node.js(Multi Thread) | 16,802.80 | 12.64MB | 14.30ms | 117 | * | 2 | Pure Node.js(Single Thread) | 8,727.14 | 6.57MB | 26.92ms | 118 | * | 3 | Iris(Go, Multi Thread) | 7,167.67 | 5.35MB | 33.51ms | 119 | * | 4 | Pure Go(Multi Thread) | 6,752.41 | 4.91MB | 35.55ms | 120 | * | 5 | Express(JS, Multi Thread) | 4,240.04 | 3.54MB | 56.68ms | 121 | * | 6 | Express(JS, Single Thread) | 2,404.82 | 2.01MB | 99.70ms | 122 | * | 7 | Pure PHP(Multi Thread) | 550.48 | 251.90KB | 27.81ms | 123 | * | 8 | Laravel(PHP, Multi Thread) | 33.48 | 216.63KB | 417.37ms | 124 | * ------------------------------------------------------------------------------------- 125 | */ 126 | ``` 127 | 128 | ## Test Source Code 129 | 130 | 131 | #### Pure Go 132 | 133 | ```go 134 | // Hello world 135 | func main() { 136 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 137 | w.Write("Hello world") 138 | }) 139 | http.ListenAndServe("127.0.0.1:8080", nil) 140 | } 141 | 142 | // Prime numbers 143 | func main() { 144 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 145 | json, err := fastjson.Marshal(getPrimes(1000)) 146 | if err != nil { 147 | panic(err) 148 | return 149 | } 150 | w.Write(json) 151 | }) 152 | http.ListenAndServe("127.0.0.1:8080", nil) 153 | } 154 | ``` 155 | 156 | #### Iris 157 | 158 | ```go 159 | // Hello World 160 | func main() { 161 | iris.Get("/", func(ctx *iris.Context) { 162 | ctx.Write("Hello world") 163 | }) 164 | iris.Listen("127.0.0.1:8080") 165 | } 166 | 167 | // Prime Numbers 168 | func main() { 169 | iris.Get("/", func(ctx *iris.Context) { 170 | ctx.JSON(200, getPrimes(1000)) 171 | }) 172 | iris.Listen("127.0.0.1:8080") 173 | } 174 | ``` 175 | 176 | #### Go Prime Number Function 177 | ```go 178 | func getPrimes(max int) []int { 179 | var i, j int 180 | sieve := map[int]bool{} 181 | primes := []int{} 182 | for i = 2; i <= max; i++ { 183 | if ok, _ := sieve[i]; !ok { 184 | primes = append(primes, i) 185 | for j = i << 1; j <= max; j += i { 186 | sieve[j] = true 187 | } 188 | } 189 | } 190 | return primes 191 | } 192 | ``` 193 | 194 | 195 | #### Pure Node.js(multi- and single-thread) 196 | 197 | ```javascript 198 | // Hello World 199 | var server = http.createServer(function (request, response) { 200 | if (request.method == "GET") { 201 | response.writeHead(200, {'Content-Type': 'text/html'}); 202 | response.write('Hello worlds'); 203 | response.end(); 204 | } 205 | }); 206 | server.listen(3000); 207 | 208 | 209 | // Prime Numbers 210 | var server = http.createServer(function (request, response) { 211 | if (request.method == "GET") { 212 | response.writeHead(200, {'Content-Type': 'text/html'}); 213 | // Notice the JSON.stringify process which is included in the operation 214 | response.write(JSON.stringify(getPrimes(1000))); 215 | response.end(); 216 | } 217 | }); 218 | server.listen(3000); 219 | ``` 220 | 221 | #### Express(multi- and single-threaded) 222 | ```javascript 223 | router.get('/', function (req, res, next) { 224 | res.send('Hello World'); 225 | }); 226 | 227 | 228 | // Get prime numbers 229 | router.get('/', function (req, res, next) { 230 | res.send(getPrimes(1000); 231 | }); 232 | ``` 233 | 234 | #### JavaScript Prime Number Function 235 | ```javascript 236 | const getPrimes = (max) => { 237 | var sieve = [], i, j, primes = []; 238 | for (i = 2; i <= max; ++i) { 239 | if (!sieve[i]) { 240 | primes.push(i); 241 | for (j = i << 1; j <= max; j += i) { 242 | sieve[j] = true; 243 | } 244 | } 245 | } 246 | return primes; 247 | }; 248 | ``` 249 | 250 | 251 | #### Pure PHP 252 | ```php 253 | // Hello world 254 | echo "Hello world"; 255 | 256 | // Prime numbers 257 | print_r(getPrimeNumbers(1000)); 258 | ``` 259 | 260 | 261 | #### Laravel 262 | ```php 263 | Route::get('/', function () { 264 | return 'Hello World'; 265 | }); 266 | 267 | Route::get('/', function () { 268 | return getPrimeNumber(1000); 269 | }); 270 | ``` 271 | 272 | #### PHP Prime Number Function 273 | ```php 274 | function getPrimeNumbers($n) 275 | { 276 | $sieve = []; 277 | for($i = 1; $i <= $n; $i++) { 278 | $sieve[$i] = $i; 279 | } 280 | 281 | $i =2; 282 | while($i * $i <= $n) { 283 | if(isset($sieve[$i])) { 284 | $k = $i; 285 | while ($k * $i <= $n) { 286 | unset($sieve[$k * $i]); 287 | $k++; 288 | } 289 | } 290 | $i++; 291 | } 292 | return $sieve; 293 | } 294 | ``` 295 | 296 | 297 | 298 | 299 | --------------------------------------------------------------------------------