From: Joshua Haberman Date: 2005-10-04T15:07:39+09:00 Subject: Re: state of blocking/nonblocking I/O --Apple-Mail-8--225002262 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed On Oct 3, 2005, at 9:21 PM, Tanaka Akira wrote: > In article <3qctcuFecn8gU1@individual.net>, > "Robert Klemme" 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. Josh --Apple-Mail-8--225002262--