Quoting [email protected], 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.
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.
You might be able to find a kqueue()/kevent() extension if you googled
for one.
Good luck, the project sounds fun.
Cheers,
Sam