On 10/19/2009 02:51 PM, Daniel Bush wrote: > Hi, > I think I'm running up against ruby 1.8.6's not so > stellar threading system. Was hoping someone > could confirm or otherwise point out some flaws. > > Note: I get reasonable performance when running on > ruby 1.9 it's just 1.8.6 that hangs like a > deadlock when I start using too many threads in > one of my test scripts. (My focus is actually > on 1.9 and jruby anyway). > > Give you an idea: > > I might get a pool of 10 acceptor threads to run > something like the following (each has their own > version of this code): > > client, client_sockaddr = @socket.accept > # Threads block on #accept. > data = client.recvfrom( 40 )[0].chomp > @mutex.synchronize do > puts "#{Thread.current} received #{data}... " > end > client.close > > on @socket which was set up like this: > > @socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) > @sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost') > @socket.bind( @sockaddr ) > @socket.listen( 100 ) This won't work. You can have only 1 acceptor thread per server socket. Typically you dispatch processing *after* the accept to a thread (either newly created or taken from a pool). I have no idea what the interpreter is going to do if you have multiple threads trying to accept from the same socket. In the best case #accept is synchronized and only one thread gets to enter it. In worse scenarios anything bad may happen. > I wanted to create a barrage of requests so next I > create a pool of requester threads which each run > something like this: > > socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) > sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) > socket.connect( sockaddr ) > socket.puts "request #{i}" > socket.close Btw, why don't you use TCPServer and TCPSocket? > All of this in one script. If I have so much as > 2 requester threads in addition to the 10 > acceptors waiting to receive their requests, 1.8.6 > just seizes up before processing anything. If I > use 2 acceptors and 2 requesters, it works. If I > use 10 acceptors, 1 requester it works. When it > does work however, it doesn't appear to schedule > threads too well; it just seems to use one all the > time - although this seems to happen only when > using sockets as opposed to a more general job > queue. See above. > I haven't submitted the full code because it uses > a threadpool library I'm still building/reviewing. I would rather do something like this (sketeched): require 'thread' queue = Queue.new workers = (1..10).map do Thread.new queue do |q| until (cl = q.deq).equal? q # process data from / for client cl begin data = cl.gets.chomp @mutex.synchronize do puts "#{Thread.current} received #{data}..." end ensure cl.close end end end end server = TCPServer.new ... while client = server.accept queue.enq client end # elsewhere TCPSocket.open do |sock| sock.puts "request" end Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/