見出し画像

Node-RED TIPS (Performance#1_loop)

Node-RED、とても便利なのですが、先日、パフォーマンスの課題が発生しました。色々やってみましたので、今回は、ループ処理のパフォーマンスの比較を記載します。

for ループ

1. Function node 内でループ処理した方が良いのか?
2. node を回した方が良いのか?

Node-RED の持つ可視性を活用するなら「2.」なのですが、パフォーマンス的には、「1.」の方が圧倒的です。

検証フロー

下のフローを用意しました。
ループ内で 100 回カウントアップするだけの処理です。

[{"id":"e24b5512.80fb18","type":"tab","label":"for_loop","disabled":false,"info":""},{"id":"1e9178ec.ca47c7","type":"function","z":"e24b5512.80fb18","name":"t1 = Date.now();","func":"msg.t1 = Date.now();\nreturn msg;","outputs":1,"noerr":0,"x":660,"y":300,"wires":[["8ff2a808.9ef4c8"]]},{"id":"dc163b00.5b14b8","type":"inject","z":"e24b5512.80fb18","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":620,"y":180,"wires":[["615c04ec.47728c"]]},{"id":"3b79fbf4.c238d4","type":"function","z":"e24b5512.80fb18","name":"t2 = Date.now();","func":"msg.t2 = Date.now();\nreturn msg;","outputs":1,"noerr":0,"x":660,"y":540,"wires":[["2c5531ad.babdce"]]},{"id":"ad979296.42ac2","type":"function","z":"e24b5512.80fb18","name":"for (100) i++","func":"for (let i2 = 0; i2 < 100; i2++) {\n    msg.i++;\n}\nreturn msg;","outputs":1,"noerr":0,"x":730,"y":420,"wires":[["9b7ac1cf.bd509"]]},{"id":"8ff2a808.9ef4c8","type":"function","z":"e24b5512.80fb18","name":"console.time('t');","func":"console.time('t');\nreturn msg;","outputs":1,"noerr":0,"x":700,"y":360,"wires":[["ad979296.42ac2"]]},{"id":"9b7ac1cf.bd509","type":"function","z":"e24b5512.80fb18","name":"console.timeEnd('t');","func":"console.timeEnd('t');\nreturn msg;","outputs":1,"noerr":0,"x":720,"y":480,"wires":[["3b79fbf4.c238d4"]]},{"id":"615c04ec.47728c","type":"function","z":"e24b5512.80fb18","name":"t1 =0; t2 = 0; i = 0;","func":"msg.t1 = 0;\nmsg.t2 = 0;\nmsg.i = 0;\nreturn msg;","outputs":1,"noerr":0,"x":670,"y":240,"wires":[["1e9178ec.ca47c7"]]},{"id":"2c5531ad.babdce","type":"debug","z":"e24b5512.80fb18","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":630,"y":600,"wires":[]},{"id":"cf56a904.f01ee8","type":"function","z":"e24b5512.80fb18","name":"","func":"msg.t1 = Date.now();\nreturn msg;","outputs":1,"noerr":0,"x":950,"y":300,"wires":[["53e566f2.347d28"]]},{"id":"16e489ec.b7dd56","type":"inject","z":"e24b5512.80fb18","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":940,"y":180,"wires":[["bfc7bc25.9e3f3"]]},{"id":"3dc5cbc9.b14a24","type":"function","z":"e24b5512.80fb18","name":"","func":"msg.t2 = Date.now();\nreturn msg;","outputs":1,"noerr":0,"x":950,"y":540,"wires":[["aa9d91d8.04672"]]},{"id":"53e566f2.347d28","type":"function","z":"e24b5512.80fb18","name":"","func":"console.time('t');\nreturn msg;","outputs":1,"noerr":0,"x":990,"y":360,"wires":[["89a8493a.5b3448"]]},{"id":"fe8d8f21.5b9ca","type":"function","z":"e24b5512.80fb18","name":"","func":"console.timeEnd('t');\nreturn msg;","outputs":1,"noerr":0,"x":990,"y":480,"wires":[["3dc5cbc9.b14a24"]]},{"id":"bfc7bc25.9e3f3","type":"function","z":"e24b5512.80fb18","name":"","func":"msg.t1 = 0;\nmsg.t2 = 0;\nmsg.i = 0;\nreturn msg;","outputs":1,"noerr":0,"x":950,"y":240,"wires":[["cf56a904.f01ee8"]]},{"id":"aa9d91d8.04672","type":"debug","z":"e24b5512.80fb18","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":950,"y":600,"wires":[]},{"id":"89a8493a.5b3448","type":"function","z":"e24b5512.80fb18","name":"if (i < 100)","func":"if (msg.i < 100) return [ msg, null ];\nreturn [ null, msg ];","outputs":2,"noerr":0,"x":1040,"y":420,"wires":[["c99c39d5.8a44c8"],["fe8d8f21.5b9ca"]]},{"id":"c99c39d5.8a44c8","type":"function","z":"e24b5512.80fb18","name":"i++","func":"msg.i++\nreturn msg;","outputs":1,"noerr":0,"x":1170,"y":380,"wires":[["89a8493a.5b3448"]]}]

左が
 > 1. Function node 内でループ処理した方が良いのか?
で、

右が
 > 2. node を回した方が良いのか?
です。

(右の Flow で、node 名が空になっている部分は、左の Flow と全く同じ処理)

検証結果

実行すると、こんな感じになります。

左の Flow は 1 ms, 右の Flow は 6 ms, ということになっています。
が、これは epoch time を使った簡易的な比較なので、より詳しく見る為に、console.time の結果も確認します。

一行目が左の Flow で 361 μs, 二行目が右の Flow で 5,753 μs です。
たった 100 回カウントアップするだけのループで既にかなりの差が出ていますね。。。
(次回以降どこかで記載しようと思いますが、作りによって、node をまたぐ時の負荷が上がってしまうようなので、この差はどんどん広がります)

ちなみに、右のフローは、割とすぐ、回数の限界がきます。

閾値は状況によって変わるようですが、今のところ、1,000 回以上ループできたことはありません。

Debug

Function node 内でループさせると、ループ中の処理を debug node で追いかけることができません。ループ内の処理を確認する必要がある場合は、node.warn() か node.error() を使いましょう。

まとめ

高パフォーマンスが必要な場合は、Function node 内でがんばりましょう!
#nodered #noderedjp #Performance #パフォーマンス

この記事が気に入ったらサポートをしてみませんか?