From: David Gurba Date: 2005-10-04T16:13:00+09:00 Subject: Re: state of blocking/nonblocking I/O Joshua Haberman wrote: > 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 > This sounds really interesting, but I don't fully understand the while loop. Nonblocking IO sends/recieves data when its ready/requested...eg. it doesn't block for the data, right? I have written some threaded applications. A java tic-tac-toe game which had players and observers of a game that all viewed a global 'board' state. Methods to modify the game state were thread safe with mutexes, how is what your saying different...? Any info appreciated... ooooo my 1st post to the mailing list :)