<div><div><div dir="auto">Hello Michael and Fred</div></div><div dir="auto"><br></div><div dir="auto">Combing both solutions gave the best result. No need to even touch the memory allocators at all and the system look stable for the last days.</div></div><div dir="auto"><br></div><div dir="auto">Michael: I’m passing a sub_binary to the child process created with your sync_fun/2. Is it still a good idea to call binary:copy/1 on this sub_bin inside the Fun? I think it’s useless because this process is garbage collected ASAP anyway.</div><div><div dir="auto"><br></div><div dir="auto">/Frank</div><div dir="auto"><br></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div dir="auto">Hello Michael</div></div><div dir="auto"><br></div><div dir="auto">Thanks again for the tip. I will update my design accordingly and let you know how it goes. </div><div dir="auto"><br></div><div dir="auto">/Frank</div><div dir="auto"><br></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 2/1/19 10:53 PM, Frank Muller wrote:<br>
> Hi Michael<br>
><br>
> All packets in transit have a “seq_id” (sequential number).<br>
><br>
> This means that in theory packet1, packet2...packetN can be checked in <br>
> parallel and in any order (which is not the case in my current <br>
> design), but they must be send to the next processing stage in order: <br>
> packet1 first, then packet2...<br>
><br>
> I would love to hear from you how can I turn this long-lived process <br>
> to multiple short-lived ones while enforcing ordering.<br>
<br>
An easy way to think about it comes from a module I used in the past <br>
called immediate_gc <br>
(<a href="https://gist.github.com/okeuday/dee991d580eeb00cd02c" rel="noreferrer" target="_blank">https://gist.github.com/okeuday/dee991d580eeb00cd02c</a>).  The sync_fun/2 <br>
function is below:<br>
<br>
<br>
sync_fun(F, A) when is_function(F), is_list(A) -><br>
     Parent = self(),<br>
     Child = erlang:spawn_opt(fun() -><br>
         Parent ! {self(), erlang:apply(F, A)},<br>
         erlang:garbage_collect()<br>
     end, [link, {fullsweep_after, 0}]),<br>
     receive<br>
         {Child, Result} -> Result<br>
     end.<br>
<br>
That is all you need to use a temporary process in a blocking way that <br>
consumes all the temporary binary data as quickly as the BEAM allows.  <br>
However, that example is more complex than it needs to be, with the <br>
child process using the fullsweep_after option and <br>
erlang:garbage_collect/0.  The extra complexity in the example is really <br>
not necessary or desirable, though it does force the garbage collection <br>
to occur as quickly as possible when consuming the temporary binary data <br>
(binary data that nothing else references).<br>
<br>
Spawn a similar child process before you start decoding a large binary, <br>
so the temporary Erlang process has a lifetime the length of the single <br>
request (packet in your situation) or less. Spawning Erlang processes is <br>
cheap, so you shouldn't hesitate to use them, just ensure they are <br>
linked so their failures may be tracked.<br>
<br>
CloudI (<a href="https://cloudi.org" rel="noreferrer" target="_blank">https://cloudi.org</a>) internal services use temporary processes <br>
for handling service requests, in a way that is tunable with the service <br>
configuration options request_pid_uses and info_pid_uses , so you can <br>
control how many requests are processed in a temporary Erlang process <br>
before a new one is created (with the exit exception being used to <br>
terminate the Erlang process with its last result).  CloudI internal <br>
services also have the hibernate service configuration option, with the <br>
hibernate based on request rate checked every few seconds (the service <br>
configuration options are described at <br>
<a href="http://cloudi.org/api.html#2_services_add_config_opts" rel="noreferrer" target="_blank">http://cloudi.org/api.html#2_services_add_config_opts</a>).<br>
<br>
The idea of using a temporary Erlang process for consuming temporary <br>
binary data, is likely unusual for people new to Erlang/Elixir and may <br>
not have found its way into Erlang/Elixir books, though it is important <br>
to know about if you want to avoid excessive memory consumption (and <br>
potentially causing the BEAM to die due to memory use).<br>
<br>
Best Regards,<br>
Michael<br>
<br>
<br>
</blockquote></div></div>
</blockquote></div></div>
</div>