From: Vlad GALU Date: 2006-04-30T01:24:54+09:00 Subject: Re: Multiplexed I/O On 4/29/06, Sam Roberts wrote: > Quoting vladgalu@gmail.com, on Sat, Apr 29, 2006 at 05:39:22PM +0900: > > I'd like to use Ruby for a quite high performance networking tool. > > In practice, writing a multithreaded C/C++ program is not pheasible > > due to the large connection pool I plan to manage, which would impose > > a very scarce stack size. From what I can see, Ruby's default I/O > > semantics are synchronous. One can opt for using IO#select though. > > Ruby threads are basically wrappers for select() aka. multiplexed i/o. > Every thread when doing something in ruby that would result in a > (potentially) blocking system call on an fd actually calls select > instead of the syscall. So, it will look to you like you have multiple > threads independently performing "blocking' i/o operations, but from a > unix/system call perspective you have one process, waiting on select > when all ruby "threads" are waiting for i/o. Thank you! It's all clear now! > > This is how you would write a high-performance C/C++ network tool > without using OS threads, too. > > > Let's just say synchronous is OK, API-wise. My question is: if I use > > one (Ruby) thread per client, would it block the whole Ruby > > interpreter while performing blocking I/O ? On my system (FreeBSD) > > ruby is linked against libpthread, for a good reason I guess. > > > Yes, but the reason is it gets threadsafe versions of C libraries, not > so it can make pthreads for each ruby Thread. > > > Could it be that it splits blocking routines to a separate (POSIX) > > thread ? > > No, it uses multiplexed i/o so ruby threads aren't blocked on i/o > in other ruby threads. > > > If not, I'll probably end up replacing the select() implementation > > with kqueue() calls in the Ruby code. > > You know best, but I don't see how this will help. If you have > so many fds that you hit the scalability limits of select() and > need kqueue, you might be in trouble with ruby unless you can > access fairly raw fds. Maybe if you do sys_read/sys_write you bypass > ruby's internal select()? Worth checking. > > Also, kqueue() itself returns an fd and kevent() is blocking... A ruby > binding for kevent() would use ruby's C APIs to select() on the fd, and > only call kevent() when it new it wouldn't block. > It depends on how you call kevent(), you can emulate select()'s behaviour when passing a zeroed timespec struct. It imediately returns, and then it's up to you to see whether you have pending events or not. > You might be able to find a kqueue()/kevent() extension if you googled > for one. I have, I took a look at Ruby/Event and Myriad before posting :) Bottom line, it would be nice if Ruby used whatever the platform it's running on has (kqueue, epoll, etc) instead of plain select(), moving the abstraction a bit lower. This should be enough for most challenges, I think. Thank you too for your hints.