Question: threads behaviour

Hi,

As ruby threads are so called green threads, what's the behaviour when
one thread is blocked on IO?
If the thread is blocked on a system call, is the whole process, ie
all threads blocked because the kernel scheduler considers the process
as blocked on IO? Are there IOs blocking a thread without blocking the
whole ruby process?

Thanks

Raphaël

I'm new to threading, but from what I've been able to find, if the
currently active thread is blocked on IO, it should block the rest of them.
At least, certain circumstances could cause that. According to (the rather
old) post at Hot XXX Images, Best Porn Pics and Free Sex Photos on www.pornfalcon.com
, it's possible to block on IO. My own tests are unable to confirm that,
even for large test sizes. My guess is that in the 7ish years since that
post, many improvements have gone into the interpreter. :wink: The post at
ruby - Thread.join blocks the main thread - Stack Overflow
has more information on ways of using them to not block each other.

Programming Ruby: The Pragmatic Programmer's Guide was
where I started for threading, but the only references I see to blocking in
it talk about the Thread.critical= method.

has a nice synopsis of the threading types between ruby implementations.

···

On Tue, 1 Mar 2011 17:45:26 +0900, Raphael Bauduin <rblists@gmail.com> wrote:

Hi,

As ruby threads are so called green threads, what's the behaviour when
one thread is blocked on IO?
If the thread is blocked on a system call, is the whole process, ie
all threads blocked because the kernel scheduler considers the process
as blocked on IO? Are there IOs blocking a thread without blocking the
whole ruby process?

Thanks

Raphaël

Hi,

As ruby threads are so called green threads, what's the behaviour when
one thread is blocked on IO?

They're only green threads on Ruby 1.8, 1.9 uses native threads.

If the thread is blocked on a system call, is the whole process, ie
all threads blocked because the kernel scheduler considers the process
as blocked on IO? Are there IOs blocking a thread without blocking the
whole ruby process?

1.8 will schedule other threads if the blocking IO is for a socket/pipe
and uses the normal Ruby IO interfaces (or the extension author was
careful). Filesystem I/O (including NFS) can block the entire process
in 1.8.

···

Raphael Bauduin <rblists@gmail.com> wrote:

--
Eric Wong

Where do you take that from? AFAIK internally Ruby 1.8.* uses non
blocking IO calls in combination with select() to be able to let other
threads work while IO is under way.

So: if IO blocks generally other threads continue to work - even on 1.8.

Cheers

robert

···

On Tue, Mar 1, 2011 at 10:27 AM, Eric Wong <normalperson@yhbt.net> wrote:

Raphael Bauduin <rblists@gmail.com> wrote:

As ruby threads are so called green threads, what's the behaviour when
one thread is blocked on IO?

They're only green threads on Ruby 1.8, 1.9 uses native threads.

If the thread is blocked on a system call, is the whole process, ie
all threads blocked because the kernel scheduler considers the process
as blocked on IO? Are there IOs blocking a thread without blocking the
whole ruby process?

1.8 will schedule other threads if the blocking IO is for a socket/pipe
and uses the normal Ruby IO interfaces (or the extension author was
careful). Filesystem I/O (including NFS) can block the entire process
in 1.8.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Eric Wong wrote:

···

Raphael Bauduin <rblists@gmail.com> wrote:

As ruby threads are so called green threads, what's the behaviour when
one thread is blocked on IO?

They're only green threads on Ruby 1.8, 1.9 uses native threads.

That's not true. The vast majority of Ruby 1.8 implementations use
native threads, and I think there is at least one Ruby 1.9
implementation which uses green threads.

jwm

Yes, I meant "blocking" from a user-visible perspective, not from a
kernel perspective. If there's an EAGAIN it'll block the current thread
from a user perspective and schedule others using select(), but not
actually block on the syscall that caused EAGAIN.

···

Robert Klemme <shortcutter@googlemail.com> wrote:

> 1.8 will schedule other threads if the blocking IO is for a socket/pipe
> and uses the normal Ruby IO interfaces (or the extension author was
> careful). Filesystem I/O (including NFS) can block the entire process
> in 1.8.

Where do you take that from? AFAIK internally Ruby 1.8.* uses non
blocking IO calls in combination with select() to be able to let other
threads work while IO is under way.

--
Eric Wong

Really? Which are those?

Cheers

  robert

···

On 02.03.2011 22:30, Jörg W Mittag wrote:

Eric Wong wrote:

Raphael Bauduin<rblists@gmail.com> wrote:

As ruby threads are so called green threads, what's the behaviour when
one thread is blocked on IO?

They're only green threads on Ruby 1.8, 1.9 uses native threads.

That's not true. The vast majority of Ruby 1.8 implementations use
native threads, and I think there is at least one Ruby 1.9
implementation which uses green threads.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

OK, but earlier you said that file system IO can block the entire process - which is not exactly true and also does not match what you said now. :slight_smile:

Cheers

  robert

···

On 03/01/2011 08:16 PM, Eric Wong wrote:

Robert Klemme<shortcutter@googlemail.com> wrote:

1.8 will schedule other threads if the blocking IO is for a socket/pipe
and uses the normal Ruby IO interfaces (or the extension author was
careful). Filesystem I/O (including NFS) can block the entire process
in 1.8.

Where do you take that from? AFAIK internally Ruby 1.8.* uses non
blocking IO calls in combination with select() to be able to let other
threads work while IO is under way.

Yes, I meant "blocking" from a user-visible perspective, not from a
kernel perspective. If there's an EAGAIN it'll block the current thread
from a user perspective and schedule others using select(), but not
actually block on the syscall that caused EAGAIN.

Robert Klemme wrote:

Eric Wong wrote:

As ruby threads are so called green threads, what's the behaviour when
one thread is blocked on IO?

They're only green threads on Ruby 1.8, 1.9 uses native threads.

That's not true. The vast majority of Ruby 1.8 implementations use
native threads, and I think there is at least one Ruby 1.9
implementation which uses green threads.

Really? Which are those?

Ruby 1.8 implementations which use native threads:

* Rubinius
* JRuby (uses JVM threads, which are native on most JVMs, certainly
    the ones that people *actually* use)
* XRuby (same)
* IronRuby (same, but for CLI threads)
* Ruby.NET (same)
* Cardinal (I think)
* ... probably a few others ...

As for a Ruby 1.9 implementation that uses green threads, I distinctly
remember reading about one, but I forgot which one. There's so many
Ruby implementations right now that it's hard to keep track of which
ones are 1.8 or 1.9 (or both), which ones have native threads or green
threads, which ones have concurrent threads or serialized threads.

(Interestingly, I haven't seen any implementations with concurrent
green threads, which IMO is the best kind of threads. Rubinius
originally planned to do concurrent green threads, but they never did.
They started off with serialized green threads, then switched to
serialized native threads and are currently in the process of
switching to concurrent native threads.)

jwm

···

On 02.03.2011 22:30, Jörg W Mittag wrote:

Raphael Bauduin<rblists@gmail.com> wrote:

Filesystem IO (regular files) doesn't return EAGAIN (at least not on
systems I'm familiar with).

···

Robert Klemme <shortcutter@googlemail.com> wrote:

On 03/01/2011 08:16 PM, Eric Wong wrote:

Robert Klemme<shortcutter@googlemail.com> wrote:

1.8 will schedule other threads if the blocking IO is for a socket/pipe
and uses the normal Ruby IO interfaces (or the extension author was
careful). Filesystem I/O (including NFS) can block the entire process
in 1.8.

Where do you take that from? AFAIK internally Ruby 1.8.* uses non
blocking IO calls in combination with select() to be able to let other
threads work while IO is under way.

Yes, I meant "blocking" from a user-visible perspective, not from a
kernel perspective. If there's an EAGAIN it'll block the current thread
from a user perspective and schedule others using select(), but not
actually block on the syscall that caused EAGAIN.

OK, but earlier you said that file system IO can block the entire
process - which is not exactly true and also does not match what you
said now. :slight_smile:

--
Eric Wong

Some JVMs started out with M:N threading (which I think is what you
mean by concurrent green threads, i.e. M green threads mapped to N
native threads, so you can get concurrency but also lightweight
threading), but as far as I know they all abandoned it due to the
overhead of managing both concurrency and lightweight thread contexts.

If there are any green-threaded JVMs out there, it's likely they're
too slow to be useful; native JIT is hard to implement atop green
threads, so green-threaded JVMs in the past were mostly interpreted.

- Charlie

···

2011/3/5 Jörg W Mittag <JoergWMittag+Ruby@googlemail.com>:

(Interestingly, I haven't seen any implementations with concurrent
green threads, which IMO is the best kind of threads. Rubinius
originally planned to do concurrent green threads, but they never did.
They started off with serialized green threads, then switched to
serialized native threads and are currently in the process of
switching to concurrent native threads.)

http://www.kernel.org/doc/man-pages/online/pages/man2/read.2.html#ERRORS

robert

···

On Tue, Mar 1, 2011 at 11:13 PM, Eric Wong <normalperson@yhbt.net> wrote:

Robert Klemme <shortcutter@googlemail.com> wrote:

On 03/01/2011 08:16 PM, Eric Wong wrote:

Robert Klemme<shortcutter@googlemail.com> wrote:

1.8 will schedule other threads if the blocking IO is for a socket/pipe
and uses the normal Ruby IO interfaces (or the extension author was
careful). Filesystem I/O (including NFS) can block the entire process
in 1.8.

Where do you take that from? AFAIK internally Ruby 1.8.* uses non
blocking IO calls in combination with select() to be able to let other
threads work while IO is under way.

Yes, I meant "blocking" from a user-visible perspective, not from a
kernel perspective. If there's an EAGAIN it'll block the current thread
from a user perspective and schedule others using select(), but not
actually block on the syscall that caused EAGAIN.

OK, but earlier you said that file system IO can block the entire
process - which is not exactly true and also does not match what you
said now. :slight_smile:

Filesystem IO (regular files) doesn't return EAGAIN (at least not on
systems I'm familiar with).

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

(Interestingly, I haven't seen any implementations with concurrent
green threads, which IMO is the best kind of threads. Rubinius
originally planned to do concurrent green threads, but they never did.
They started off with serialized green threads, then switched to
serialized native threads and are currently in the process of
switching to concurrent native threads.)

Some JVMs started out with M:N threading (which I think is what you
mean by concurrent green threads, i.e. M green threads mapped to N
native threads, so you can get concurrency but also lightweight
threading), but as far as I know they all abandoned it due to the
overhead of managing both concurrency and lightweight thread contexts.

It would also seem inefficient from the point of view that the OS does
already do all the tasks necessary for thread scheduling. So adding
another layer which duplicates these things would really only make
sense if the scheduling inside the process could benefit from
knowledge about the application's (Ruby interpreter in this case)
behavior and thus yield significantly better results than relying on
OS scheduling does. But, as you said, it's really the question
whether there is a runtime benefit and whether it's worth the added
complexity in the interpreter.

If there are any green-threaded JVMs out there, it's likely they're
too slow to be useful; native JIT is hard to implement atop green
threads, so green-threaded JVMs in the past were mostly interpreted.

Thanks for all those insights, Charles and Jörg!

Kind regards

robert

···

2011/3/6 Charles Oliver Nutter <headius@headius.com>:

2011/3/5 Jörg W Mittag <JoergWMittag+Ruby@googlemail.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

From read(2) - Linux manual page

  Many file systems and disks were considered to be fast enough
  that the implementation of O_NONBLOCK was deemed unnecessary.
  So, O_NONBLOCK may not be available on files and/or disks.

From what I've seen, setting O_NONBLOCK doesn't error, but read() never
actually respects it on ext{2,3,4} even when a disk is horribly slow.

···

Robert Klemme <shortcutter@googlemail.com> wrote:

On Tue, Mar 1, 2011 at 11:13 PM, Eric Wong <normalperson@yhbt.net> wrote:
> Filesystem IO (regular files) doesn't return EAGAIN (at least not on
> systems I'm familiar with).

read(2) - Linux manual page

--
Eric Wong