>From what I can see, this is more a pooling, but it has similarities to what I described.<br><br><div class="gmail_quote">On Wed, Feb 27, 2013 at 12:45 AM, Jayson Barley <span dir="ltr"><<a href="mailto:jayson.barley@gmail.com" target="_blank">jayson.barley@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div>I did something similar for a gated worker pool. It allowed me to slow the incoming data to only as fast as my workers are able to process it.<br>
<br></div>From the worker process:<br>handle_cast(get_data, State = #state{data=Data}) -><br>
gp_server:child_data(Data),<br> {noreply, State#state{data=undefined}};<br>handle_cast(run, State = #state{worker_fun=Fun, data_provider={Module, Function, Args}, data=undefined}) Input = apply(Module, Function, Args),<br>
Data = apply(Fun, Input),<br> gp_server:child_ready(self()),<br> {noreply, State#state{data=Data}}.<br><br><br><br></div>From the server process:<br>handle_call(get_data, _From, State = #state{ready_children=[Child | Rest], working_children=Working}) -><br>
Reply = gen_server:call(Child, get_data),<br> {reply, Reply, State#state{ready_children=Rest, working_children=[Child | Working]}}.<br><br>handle_cast({ready, Child}, State = #state{ready_children=Children, working_children=Working}) -><br>
Rest = lists:delete(Child, Working),<br> {noreply, State#state{ready_children=[Child | Children], working_children=Rest}}.<br><br><br><br></div>It worked well for how I was using it. <br></div><div class="HOEnZb">
<div class="h5"><div class="gmail_extra">
<br><br><div class="gmail_quote">On Sat, Feb 16, 2013 at 8:01 AM, sasa <span dir="ltr"><<a href="mailto:sasa555@gmail.com" target="_blank">sasa555@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Having thought more, I realized the original approach can be simplified. This would be the modified version:<div><br></div><div>1. The facade keeps track whether the worker is available or it is working.</div><div>2. Upon receiving a message, the facade joins it with the messages already in the queue. Then, if the worker is available, it immediately sends data to it, and clears its own queue.</div>
<div>3. When the worker receives the notification, it performs the work, then it notifies the facade that it is available.</div><div>4. When the facade receives the information that the worker is available, if there is new data available, it will immediately send it to the worker as explained in 2.</div>
<div><br></div><div>Thank you for your question, it had made me realized there is place for simplification.</div><div><br></div><div><div class="gmail_quote"><div>On Sat, Feb 16, 2013 at 5:58 AM, Erik Søe Sørensen <span dir="ltr"><<a href="mailto:eriksoe@gmail.com" target="_blank">eriksoe@gmail.com</a>></span> wrote:<br>
</div><div><div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><p dir="ltr">I must confess that (at least at this late hour) your Step 2 confuses me.<br>
Why not just 1+3+4, or indeed *just* step 2?</p>
<p dir="ltr">Regards, <br>
/Erik</p>
<div class="gmail_quote">Den 15/02/2013 16.47 skrev "sasa" <<a href="mailto:sasa555@gmail.com" target="_blank">sasa555@gmail.com</a>>:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div>
Hello,<div><br></div><div>A while ago I encountered the following situation:</div><div><br></div><div>I had the gen_server base process P which would receive messages, and handle them by sending some data over the network. The messages were coming faster than they were being sent. I established the reason for this was the "randomness" of my network conditions. I also established that sending more messages at once was almost as fast as sending one message, i.e. the network push time wasn't highly dependent on the message size.</div>
<div><br></div><div>To tackle this in a generic way, I devised an approach which has served me well in multiple places. I was repeatedly googling whether some similar solution exists, but I couldn't find it. Now, I'm not sure if I have reinvented a wheel, or the approach is not optimal, so I'm asking if you are aware of similar approaches, and are there any faults in this one?</div>
<div><br></div><div>The approach I took is following:</div><div><br></div><div><div>I split the server in two processes: the "facade" and the worker. The facade acceptes requests from clients, and stores them internally. While the worker is doing its work, new messages are stored in the facade. When the worker is available, it will take all accumulated messages from the facade and process them.</div>
</div><div><br></div><div>These are the steps:</div><div>1. The facade receives messages, stores data in its list, and notifies the worker (without sending actual data), that some work is ready.</div><div>2. Upon receiving the notification, the worker first flushes its message queue by doing repeated receive ... after 0 as long as there are messages in the queue.</div>
<div>3. Then the worker pulls all messages from the facade. This is a gen_server:call to the facade which will return all messages, and at the same time remove them from its state.</div><div>4. Finally, the worker processes all messages.</div>
<div><br></div><div><br></div><div>I found this approach useful because the delay on the worker adapts to the incoming message rate. </div><div>If the worker can handle messages at the incoming rate, everything works without delay. </div>
<div>If messages can't be handled at the incoming rate, the worker's delay will increase to accomodate the higher load. In other words, the worker will try to compensate the load by bulk processing messages. Obviously, this is useful only when process_time(N messages) < N * process_time(1 message).</div>
<div><br></div><div>Another benefit I found is that I can vary the implementation of the facade i.e. I can store messages using different algorithms. In the first implementation, I stored messages in a list. In one variation, I used hash which allowed me to eliminate duplicate messages. Another variant was truncation of the list, which allowed me to discard old messages if the queue was getting too large.</div>
<div><br></div><div>As I said, this has served me well in the production for more than a year, and I have finally found the time to make a generic library out of it. Before putting it public, I'd like to check if there are similar solutions, or alternative approaches?</div>
<div><br></div><div>Thanks, and best regards,</div><div>Sasa</div>
<br></div></div>_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
<br></blockquote></div>
</blockquote></div></div></div><br></div>
<br>_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
<br></blockquote></div><br></div>
</div></div></blockquote></div><br>