Re: performance benchmark of async-design-patterns - recursive-callbacks vs. promises vs. async/await

2018-04-29 Thread Michael J. Ryan
Nice... And not really surprising.  I am slightly surprised async/await is
so close to promises.  Which means that improving promises performance
should probably be a priority.  I still feel the easier to reason with code
is well worth it, given many apps now scale horizontally.

On Sun, Apr 29, 2018, 10:31 kai zhu  wrote:

> fyi, here are some benchmark results of nodejs' client-based http-request
> throughput, employing various async-design-patterns (on a 4gb linode box).
>  overall, recursive-callbacks seem to ~15% faster than both async/await and
> promises (~3000 vs ~2600 client-http-request/s).
>
> ```shell
> $ REQUESTS_PER_TICK=10 node example.js
>
> state 1 - node (v9.11.1)
> state 2 - http-server listening on port 3000
> ...
> state 3 - clientHttpRequestWithRecursiveCallback - flooding http-server
> with request "http://localhost:3000;
> state 5 - clientHttpRequestWithRecursiveCallback - testRun #99
> state 5 - clientHttpRequestWithRecursiveCallback - requestsTotal = 14690
> (in 5009 ms)
> state 5 - clientHttpRequestWithRecursiveCallback - requestsPassed = 7349
> state 5 - clientHttpRequestWithRecursiveCallback - requestsFailed = 7341 ({
> "statusCode - 500": true
> })
> state 5 - clientHttpRequestWithRecursiveCallback - 2933 requests / second
> state 5 - mean requests / second = {
> "clientHttpRequestWithRecursiveCallback": "3059 (156 sigma)",
> "clientHttpRequestWithPromise": "2615 (106 sigma)",
> "clientHttpRequestWithAsyncAwait": "2591 (71 sigma)"
> }
> ```
>
>
> you can reproduce the benchmark-results by running this
> zero-dependency/zero-config, standalone nodejs script below:
>
>
> ```js
> /*
>  * example.js
>  *
>  * this zero-dependency example will benchmark nodejs' client-based
> http-requests throughput,
>  * using recursive-callback/promise/async-await design-patterns.
>  *
>  * the program will make 100 test-runs (randomly picking a design-pattern
> per test-run),
>  * measuring client-based http-requests/seconde over a 5000 ms interval.
>  * it will save the 16 most recent test-runs for each design-pattern,
>  * and print the mean and standard deviation.
>  * any test-run with unusual errors (timeouts, econnreset, etc),
>  * will be discarded and not used in calculations
>  *
>  * the script accepts one env variable $REQUESTS_PER_TICK, which defaults
> to 10
>  * (you can try increasing it if you have a high-performance machine)
>  *
>  *
>  *
>  * example usage:
>  * $ REQUESTS_PER_TICK=10 node example.js
>  *
>  * example output:
>  *
>  * state 1 - node (v9.11.1)
>  * state 2 - http-server listening on port 3000
>  * ...
>  * state 3 - clientHttpRequestWithRecursiveCallback - flooding http-server
> with request "http://localhost:3000;
>  * state 5 - clientHttpRequestWithRecursiveCallback - testRun #99
>  * state 5 - clientHttpRequestWithRecursiveCallback - requestsTotal =
> 14690 (in 5009 ms)
>  * state 5 - clientHttpRequestWithRecursiveCallback - requestsPassed = 7349
>  * state 5 - clientHttpRequestWithRecursiveCallback - requestsFailed =
> 7341 ({
>  * "statusCode - 500": true
>  * })
>  * state 5 - clientHttpRequestWithRecursiveCallback - 2933 requests /
> second
>  * state 5 - mean requests / second = {
>  * "clientHttpRequestWithRecursiveCallback": "3059 (156 sigma)",
>  * "clientHttpRequestWithPromise": "2615 (106 sigma)",
>  * "clientHttpRequestWithAsyncAwait": "2591 (71 sigma)"
>  * }
>  *
>  * state 6 - process.exit(0)
>  */
>
> /*jslint
> bitwise: true,
> browser: true,
> maxerr: 4,
> maxlen: 100,
> node: true,
> nomen: true,
> regexp: true,
> stupid: true
> */
>
> (function () {
> 'use strict';
> var local;
> local = {};
>
> // require modules
> local.http = require('http');
> local.url = require('url');
>
> /* jslint-ignore-begin */
> local.clientHttpRequestWithAsyncAwait = async function (url, onError) {
> /*
>  * this function will make an http-request using async/await
> design-pattern
>  */
> var request, response, timerTimeout;
> try {
> response = await new Promise(function (resolve, reject) {
> // init timeout
> timerTimeout = setTimeout(function () {
> reject(new Error('timeout - 2000 ms'));
> }, 2000);
> request = local.http.request(local.url.parse(url),
> resolve);
> request.on('error', reject);
> request.end();
> });
> await new Promise(function (resolve, reject) {
> // ignore stream-data
> response.on('data', local.nop);
> if (response.statusCode >= 400) {
> reject(new Error('statusCode - ' +
> response.statusCode));
> return;
> }
> response.on('end', resolve);
> response.on('error', reject);
> });
> } catch 

performance benchmark of async-design-patterns - recursive-callbacks vs. promises vs. async/await

2018-04-29 Thread kai zhu
fyi, here are some benchmark results of nodejs' client-based http-request 
throughput, employing various async-design-patterns (on a 4gb linode box).  
overall, recursive-callbacks seem to ~15% faster than both async/await and 
promises (~3000 vs ~2600 client-http-request/s).

```shell
$ REQUESTS_PER_TICK=10 node example.js

state 1 - node (v9.11.1)
state 2 - http-server listening on port 3000
...
state 3 - clientHttpRequestWithRecursiveCallback - flooding http-server with 
request "http://localhost:3000;
state 5 - clientHttpRequestWithRecursiveCallback - testRun #99
state 5 - clientHttpRequestWithRecursiveCallback - requestsTotal = 14690 (in 
5009 ms)
state 5 - clientHttpRequestWithRecursiveCallback - requestsPassed = 7349
state 5 - clientHttpRequestWithRecursiveCallback - requestsFailed = 7341 ({
"statusCode - 500": true
})
state 5 - clientHttpRequestWithRecursiveCallback - 2933 requests / second
state 5 - mean requests / second = {
"clientHttpRequestWithRecursiveCallback": "3059 (156 sigma)",
"clientHttpRequestWithPromise": "2615 (106 sigma)",
"clientHttpRequestWithAsyncAwait": "2591 (71 sigma)"
}
```


you can reproduce the benchmark-results by running this 
zero-dependency/zero-config, standalone nodejs script below:


```js
/*
 * example.js
 *
 * this zero-dependency example will benchmark nodejs' client-based 
http-requests throughput,
 * using recursive-callback/promise/async-await design-patterns.
 *
 * the program will make 100 test-runs (randomly picking a design-pattern per 
test-run),
 * measuring client-based http-requests/seconde over a 5000 ms interval.
 * it will save the 16 most recent test-runs for each design-pattern,
 * and print the mean and standard deviation.
 * any test-run with unusual errors (timeouts, econnreset, etc),
 * will be discarded and not used in calculations
 *
 * the script accepts one env variable $REQUESTS_PER_TICK, which defaults to 10
 * (you can try increasing it if you have a high-performance machine)
 *
 *
 *
 * example usage:
 * $ REQUESTS_PER_TICK=10 node example.js
 *
 * example output:
 *
 * state 1 - node (v9.11.1)
 * state 2 - http-server listening on port 3000
 * ...
 * state 3 - clientHttpRequestWithRecursiveCallback - flooding http-server with 
request "http://localhost:3000;
 * state 5 - clientHttpRequestWithRecursiveCallback - testRun #99
 * state 5 - clientHttpRequestWithRecursiveCallback - requestsTotal = 14690 (in 
5009 ms)
 * state 5 - clientHttpRequestWithRecursiveCallback - requestsPassed = 7349
 * state 5 - clientHttpRequestWithRecursiveCallback - requestsFailed = 7341 ({
 * "statusCode - 500": true
 * })
 * state 5 - clientHttpRequestWithRecursiveCallback - 2933 requests / second
 * state 5 - mean requests / second = {
 * "clientHttpRequestWithRecursiveCallback": "3059 (156 sigma)",
 * "clientHttpRequestWithPromise": "2615 (106 sigma)",
 * "clientHttpRequestWithAsyncAwait": "2591 (71 sigma)"
 * }
 *
 * state 6 - process.exit(0)
 */

/*jslint
bitwise: true,
browser: true,
maxerr: 4,
maxlen: 100,
node: true,
nomen: true,
regexp: true,
stupid: true
*/

(function () {
'use strict';
var local;
local = {};

// require modules
local.http = require('http');
local.url = require('url');

/* jslint-ignore-begin */
local.clientHttpRequestWithAsyncAwait = async function (url, onError) {
/*
 * this function will make an http-request using async/await design-pattern
 */
var request, response, timerTimeout;
try {
response = await new Promise(function (resolve, reject) {
// init timeout
timerTimeout = setTimeout(function () {
reject(new Error('timeout - 2000 ms'));
}, 2000);
request = local.http.request(local.url.parse(url), resolve);
request.on('error', reject);
request.end();
});
await new Promise(function (resolve, reject) {
// ignore stream-data
response.on('data', local.nop);
if (response.statusCode >= 400) {
reject(new Error('statusCode - ' + response.statusCode));
return;
}
response.on('end', resolve);
response.on('error', reject);
});
} catch (error) {
// cleanup timerTimeout
clearTimeout(timerTimeout);
// cleanup request and response
if (request) {
request.destroy();
}
if (response) {
response.destroy();
}
onError(error);
return;
}
onError();
};
/* jslint-ignore-end */

local.clientHttpRequestWithPromise = function (url, onError) {
/*
 * this function will make an http-request using promise design-pattern
 */
var request, response,