Joshua Haberman wrote:
> On Oct 3, 2005, at 9:21 PM, Tanaka Akira wrote:
>> In article <3qctcuFecn8gU1 / individual.net>,
>>   "Robert Klemme" <bob.news / gmx.net> writes:
>>
>>
>>> I have one question on this matter which I still don't understand
>>> (I'm not
>>> so deep into C stdlib IO variants so please bear with me): why
>>> would anybody
>>> want to use nonblocking IO (on the Ruby level, e.g. IO#read might
>>> not have
>>> read anything on return even if the stream is not closed) in the
>>> light of
>>> Ruby threads?  I mean, with that one would have to build the
>>> multiplexing in
>>> Ruby which is already present in the interpreter with multiple
>>> Ruby threads?
>>> Are there situations that I'm not aware of where this is useful /
>>> needed?
>>>
>>
>> It is an interesting question I also have.
>>
>> I asked it several times, so I know some answers.
>>
>> 1. GUI framework has its own event driven framework.
>>
>>   If a callback blocks, it blocks entire GUI.  It is not
>>   acceptable.
>>
>> 2. High performance network server has its own event driven
>>    framework.
>>
>>   Some high performance network servers use an application
>>   level event driven framework.  If an event handler blocks,
>>   it blocks entire application.  It is not acceptable.
>>
>>   However I'm not sure that it is appropriate to implement
>>   a high performance server in Ruby.
>>
>> If an application level event driven framework is used,
>> application level nonblocking I/O operations are required.
>>
>> If there are other usages, I'd like to know.
>
> Nonblocking I/O is useful if you are a server with some kind of
> complex, global state, and lots of clients that can act on that
> state.  A good example would be a gaming server.  If you handle every
> client in its own thread, you need a big, coarse lock around your
> global state.  Once you're doing that, what's the point of
> multithreading?  It just makes things more complicated, and your
> program's execution more difficult to understand.
>
> You might have many IO objects open that are interrelated.  Say your
> program logic is something like:
>
> when there's data available on object A, process it and send the
> results to B and C
> when there's data available on object B, process it and send the
> results to A and C
> when there's data available on object C, process it and send the
> results to A and B
>
> How should I break this down into threads?  Three threads that block-
> on-read for A, B, and C?  But what if A and B get data at the same
> time?  They might interleave their writes to C.  Do I put a mutex
> around C?
>
> For this case, it's a lot easier and more natural to write a main
> loop like:
>
> while true
>      (read_ready, write_ready, err) = IO.select([A, B, C])
>      read_ready.each { |io|
>          output = process(io.read)
>          [A, B, C].each { |client| client.write(output) unless client
> == io }
>      }
> end
>
> Nonblocking I/O gives you more control over the execution of your
> program, and frees you from the worries of synchronizing between
> threads.  And it's simpler than using threads for programs that
> follow certain patterns.

Thanks for the feedback.  Even in this case I'd probably choose a
different architecture.  I dunno which of these is easier but here's how
I'd do it:

Have a thread per open client connection that reads requests.  Requests
are put into a queue (thread safe!).  Then I'd have a number of workers
that fetch from the task queue and do the work.  Either each worker sends
results directly to affected clients or puts results into a second queue
from which a number of sender threads fetch their tasks and send
responses.  There could also be dedicated sender threads per client.

If there are no dedicated sender threads you would need just a single
point of synchronization (apart from what queue does internally) for the
sending socket in order to prevent multiple responses to interfere (if
it's possible that a request is received while the answer to another
request is being processed).

Kind regards

    robert