2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Node-REDAdvent Calendar 2024

Day 1

Node-RED: split-joinのリソース消費対策

Last updated at Posted at 2024-11-17

Node-REDのsplitノードとjoinノード(split-join)は簡単に非同期処理を実行できて便利です。しかし、msgオブジェクトに大量データを載せているとmsg.payloadの配列要素数だけmsgオブジェクトのクローン(ディープコピー)が作成されるので、リソースを大量に消費してしまいます。
split-joinを使わずないで順次処理にする方法もありますが、それでは処理効率が落ちてしまいますので、多段でsplit-joinを使う方法を紹介します。

やりたいこと(順次処理の例)

以下のような順次処理を考えてみましょう。
image.png
set dataでは以下のような処理をします。

msg.original = {a:1, bigData:[1,2,3]}
msg.payload = msg.original.bigData;
return msg;

元データをmsg.originalに残しておいて、msg.payloadのデータを処理します。しかしこれはうまく動きません。
image.png
ディープコピーされていないので、msg.originalも更新されてしまいました。

非同期処理の例

順次処理でもmsg.original.bigDataをディープコピーすれば良いのですが、ここではsplit-joinを使います。
image.png
これはうまく動作します。
image.png
splitノードではpayloadの配列を分解して複数のmsgオブジェクトを作ります。その際にmsgオブジェクトをディープコピーしてクローンを作るからです。
この例のようなデータ量であれば問題にならないのですが、処理すべきデータが何千何万と大量の場合は、msg.originalにあるデータが何千倍何万倍に増えますから、メモリを大量消費するのはもちろん、オブジェクト生成やガベージコレクションでCPUも消費します。この例の場合はmsg.originalをあきらめればよいのですが、後続処理で使う場合はそうもいきません。

対策

そこでmsg.originalを含むmsgのクローンを別経路で渡す方法を考えました。
image.png
clone & deleteでは受け取ったメッセージのクローンを作成した後、各データの処理に不要でリソースを消費してしまうmsg.originalを消します。
そして元のmsg.payloadと作成したクローンを配列にしてmsg.payloadにセットします。

let tmp = RED.util.cloneMessage(msg);
msg.payload = [msg.payload, tmp]
delete msg.original;
return msg;

splitではmsgオブジェクトがクローンされますが、すでにmsg.originalはdeleteされているのでリソースを消費しません。
処理の後はmake answerでmsg.originalのあるオブジェクトを元に処理結果を統合してmsgオブジェクトとします。

let newMsg = msg.payload.pop();
newMsg.payload = msg.payload[0];
return newMsg;

いかがでしょう?
split-joinのリソース消費対策としてsplit-joinを使うというお話でした。

今回のソース


[{"id":"958470b8ecc39638","type":"tab","label":"split-joinのリソース消費対策","disabled":false,"info":"","env":[]},{"id":"2c373086b3fddeae","type":"group","z":"958470b8ecc39638","name":"main flow","style":{"label":true,"fill":"#bfdbef"},"nodes":["d7d55392242b9a9a","b6aabbb0b2f880ec","611750d412847cbb","4490b9bd936f8a3b"],"x":394,"y":159,"w":452,"h":182},{"id":"fc66bbd59f785bba","type":"group","z":"958470b8ecc39638","name":"main flow","style":{"label":true,"fill":"#bfdbef"},"nodes":["73014c3b0ff64176","e7a7df6990978b28","5c23a279fe16a849"],"x":154,"y":539,"w":452,"h":142},{"id":"844fc2129f6d3f47","type":"group","z":"958470b8ecc39638","name":"main flow","style":{"label":true,"fill":"#bfdbef"},"nodes":["1b04297374dd9e7d","72424f48fdfb6574","1561efd334fa288b"],"x":254,"y":839,"w":352,"h":162},{"id":"3ad2e415b7deed04","type":"inject","z":"958470b8ecc39638","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":100,"wires":[["099b0c295c62bc6b"]]},{"id":"28cc6a2709bea9dd","type":"debug","z":"958470b8ecc39638","name":"GOAL","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":770,"y":380,"wires":[]},{"id":"03cbd7df614ba4ae","type":"function","z":"958470b8ecc39638","name":"clone & delete","func":"let tmp = RED.util.cloneMessage(msg);\nmsg.payload = [msg.payload, tmp]\ndelete msg.original;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":100,"wires":[["9c2affcfaeceff25"]]},{"id":"099b0c295c62bc6b","type":"function","z":"958470b8ecc39638","name":"set data","func":"msg.original = {a:1, bigData:[1,2,3]}\nmsg.payload = msg.original.bigData;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":100,"wires":[["03cbd7df614ba4ae"]]},{"id":"9c2affcfaeceff25","type":"split","z":"958470b8ecc39638","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":170,"y":160,"wires":[["d8f24cf6ae0fc3c6"]]},{"id":"d6a1b80651d629e7","type":"join","z":"958470b8ecc39638","name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":450,"y":380,"wires":[["45b6fe62ade125e3"]]},{"id":"45b6fe62ade125e3","type":"function","z":"958470b8ecc39638","name":"make answer","func":"let newMsg = msg.payload.pop();\nnewMsg.payload = msg.payload[0];\nreturn newMsg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":380,"wires":[["28cc6a2709bea9dd"]]},{"id":"d7d55392242b9a9a","type":"split","z":"958470b8ecc39638","g":"2c373086b3fddeae","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":470,"y":240,"wires":[["611750d412847cbb","4490b9bd936f8a3b"]]},{"id":"b6aabbb0b2f880ec","type":"join","z":"958470b8ecc39638","g":"2c373086b3fddeae","name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":530,"y":300,"wires":[["d6a1b80651d629e7"]]},{"id":"611750d412847cbb","type":"debug","z":"958470b8ecc39638","g":"2c373086b3fddeae","name":"without msg.original","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":660,"y":200,"wires":[]},{"id":"d8f24cf6ae0fc3c6","type":"switch","z":"958470b8ecc39638","name":"msg.parts.index == 0?","property":"parts.index","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":220,"y":280,"wires":[["d7d55392242b9a9a"],["d6a1b80651d629e7"]]},{"id":"4490b9bd936f8a3b","type":"function","z":"958470b8ecc39638","g":"2c373086b3fddeae","name":"msg.payload = msg.payload * 2","func":"msg.payload = msg.payload * 2;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":240,"wires":[["b6aabbb0b2f880ec"]]},{"id":"52e56e33b02a64a6","type":"inject","z":"958470b8ecc39638","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":500,"wires":[["3ced34213b39f516"]]},{"id":"fa4f732f3d9e8f8f","type":"debug","z":"958470b8ecc39638","name":"GOAL","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":690,"y":640,"wires":[]},{"id":"3ced34213b39f516","type":"function","z":"958470b8ecc39638","name":"set data","func":"msg.original = {a:1, bigData:[1,2,3]}\nmsg.payload = msg.original.bigData;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":500,"wires":[["73014c3b0ff64176"]]},{"id":"73014c3b0ff64176","type":"split","z":"958470b8ecc39638","g":"fc66bbd59f785bba","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":230,"y":580,"wires":[["5c23a279fe16a849"]]},{"id":"e7a7df6990978b28","type":"join","z":"958470b8ecc39638","g":"fc66bbd59f785bba","name":"","mode":"auto","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":"false","timeout":"","count":"","reduceRight":false,"x":290,"y":640,"wires":[["fa4f732f3d9e8f8f"]]},{"id":"5c23a279fe16a849","type":"function","z":"958470b8ecc39638","g":"fc66bbd59f785bba","name":"msg.payload = msg.payload * 2","func":"msg.payload = msg.payload * 2;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":580,"wires":[["e7a7df6990978b28"]]},{"id":"09fe23de37bd79bf","type":"inject","z":"958470b8ecc39638","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":800,"wires":[["1981800cb815e49d"]]},{"id":"decb81d9ee51f1eb","type":"debug","z":"958470b8ecc39638","name":"GOAL","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":690,"y":960,"wires":[]},{"id":"1981800cb815e49d","type":"function","z":"958470b8ecc39638","name":"set data","func":"msg.original = {a:1, bigData:[1,2,3]}\nmsg.payload = msg.original.bigData;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":800,"wires":[["1b04297374dd9e7d"]]},{"id":"1b04297374dd9e7d","type":"function","z":"958470b8ecc39638","g":"844fc2129f6d3f47","name":"msg.payload[0] = msg.payload[0] * 2;","func":"msg.payload[0] = msg.payload[0] * 2;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":880,"wires":[["72424f48fdfb6574"]]},{"id":"72424f48fdfb6574","type":"function","z":"958470b8ecc39638","g":"844fc2129f6d3f47","name":"msg.payload[1] = msg.payload[1] * 2","func":"msg.payload[1] = msg.payload[1] * 2; \nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":920,"wires":[["1561efd334fa288b"]]},{"id":"1561efd334fa288b","type":"function","z":"958470b8ecc39638","g":"844fc2129f6d3f47","name":"msg.payload[2] = msg.payload[2] * 2","func":"msg.payload[2] = msg.payload[2] * 2;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":960,"wires":[["decb81d9ee51f1eb"]]},{"id":"4c9e32f9d4713738","type":"comment","z":"958470b8ecc39638","name":"順次処理","info":"","x":100,"y":740,"wires":[]},{"id":"c63214a17a7c7815","type":"comment","z":"958470b8ecc39638","name":"非同期処理","info":"","x":100,"y":440,"wires":[]},{"id":"369129de3c31c249","type":"comment","z":"958470b8ecc39638","name":"リソース対策済み非同期処理","info":"","x":180,"y":40,"wires":[]}]
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?