views:

414

answers:

3

I can see that scala can solve the Producer-Consumer problem using actors. There is a couple of examples on the web but what is worrying me is the unlimited growth of an actor's mailbox.

Suppose the producer produces on a much faster rate than the consumer can consume. Using the traditional synchronized threads approach, I can set up a buffer size and if the buffer is full, I can ask the producer to wait. The scala Actor Model approaches that I have seen so far use the mailbox as a "buffer". But what if a consumer receives too many messages from the producer? The mailbox will keep growing and eventually the program will crash? Can actors specify mailbox size limit or is there some other elegant way of dealing with this in scala?

+8  A: 

You can create an actor that acts as a buffer between the producer and consumer. The buffer checks out its mailbox to its loop data. It sends back an "overload" message to the producer when the number of buffered products is too high; and sends a "clear" message once everything is back in order. In case of too many messages it simply drops incoming ones (or oldest ones).

The consumer actively requests for products from the buffer, which in turn sends back one product. If the buffer is empty, the consumer keeps waiting for the input.

The producer sends products to the buffer actor. If it receives an "overload" message it can stop production, or it can continue producing, knowing the fact that the products might get dropped.

Of course this logic could directly be implemented into the producer or consumer itself, but a separate buffer will allow you to introduce multiple producers and/or consumers more easily.

Zed
+3  A: 

The Actor.mailboxSize method returns the number of pending messages in the Actor's mailbox.

This can be used for throttling the producer in various ways.

For example, one possibility could be,

The producer checks if the consumer's mailboxSize is greater than some threshold. If it is, then it sends a SpecialMessage to the consumer, and blocks on a semaphore. When the consumer receives this SpecialMessage it releases the semaphore. The producer can now merrily continue it's business.

This avoids polling as well as any dropped messages.

HRJ
I like how your approach avoids polling. I will use it in conjunction with the first answer.
tilish
Polling seems more appropriate to me than making the consumer's mailbox a "shared state" between two actors.
Zed
Polling is often better from a purely programming perspective, but semaphores are often better from a hardware utilization perspective. Depends on your exact situation as to which should be selected.
Brian Knoblauch
@Zed The consumer's mailbox IS shared state! Otherwise the producer wouldn't be able to send any messages to it :)
HRJ
A: 

How does Actor.mailboxSize scale? Does it lock? Does it count the elements of the mailbox?

Eirik
Eirik, I'm tempted to answer your question but posting another set of questions and answers under the main question makes things a bit disorganized. Please ask your question here after you make sure it hasn't been asked before,http://stackoverflow.com/questions/askHave a quick scan through the stackoverflow FAQ too,http://stackoverflow.com/faq
tilish