{"id":227,"date":"2007-01-15T09:55:10","date_gmt":"2007-01-15T07:55:10","guid":{"rendered":"http:\/\/www.lucas-nussbaum.net\/blog\/?p=227"},"modified":"2007-01-15T09:55:10","modified_gmt":"2007-01-15T07:55:10","slug":"ruby-native-threading","status":"publish","type":"post","link":"https:\/\/www.lucas-nussbaum.net\/blog\/?p=227","title":{"rendered":"ruby &#038; native threading"},"content":{"rendered":"<p><a href=\"http:\/\/www.bononia.it\/~zack\/\">Stefano Zacchiroli<\/a> <a href=\"http:\/\/www.bononia.it\/~zack\/blog\/\/posts\/2007\/01\/functional_ruby_s_threads.html\">said<\/a>:<\/p>\n<blockquote><p>To balance this, according to my first read of Ruby&#8217;s threading capability, it&#8217;s my impression that not only at most one thread can execute Ruby code at a time (limitation shared by OCaml, due to the non-distributed nature of mark and sweep garbage collectors), but also a thread blocked on a syscall will block all other threads to run.<\/p>\n<p>Dumb Ruby threads (but I still hope I&#8217;m wrong &#8230;)<\/p><\/blockquote>\n<p>This is not totally true:<\/p>\n<ul>\n<li>Yes, Ruby threads are user-level: you won&#8217;t get speedup from dual-cores or dual-processors system. In python, <a href=\"http:\/\/www.atdot.net\/yarv\/rc2006_sasada_yarv_on_rails.pdf\">this presentation<\/a> claims (slide 39) that python threads are mapped to native threads, but that a giant lock always prevents the execution of more than one thread at a time (so library writers don&#8217;t have to write thread-safe code).<\/li>\n<li>The ruby interpreter tries very hard to map blocking syscalls to their non-blocking counterparts (for example, all I\/Os are passed to a select() call). This gets really dirty when you mix I\/O and other syscalls. For example, see the strace output the following Ruby code:\n<pre><tt><b><font color=\"#000080\">require<\/font><\/b> <font color=\"#FF0000\">'thread'<\/font>\r\nth1 <font color=\"#990000\">=<\/font> Thread<font color=\"#990000\">::<\/font>new <b><font color=\"#0000FF\">do<\/font><\/b>\r\n  pid <font color=\"#990000\">=<\/font> fork <font color=\"#FF0000\">{<\/font> sleep <font color=\"#993399\">2<\/font> <font color=\"#FF0000\">}<\/font>\r\n  Process<font color=\"#990000\">::<\/font><b><font color=\"#000000\">waitpid<\/font><\/b><font color=\"#990000\">(<\/font>pid<font color=\"#990000\">)<\/font>\r\n  puts <font color=\"#FF0000\">\"Finished.\"<\/font>\r\n<b><font color=\"#0000FF\">end<\/font><\/b>\r\nth2 <font color=\"#990000\">=<\/font> Thread<font color=\"#990000\">::<\/font>new <b><font color=\"#0000FF\">do<\/font><\/b>\r\n  f <font color=\"#990000\">=<\/font> STDIN<font color=\"#990000\">.<\/font>read\r\n  puts <font color=\"#FF0000\">\"Finished2.\"<\/font>\r\n<b><font color=\"#0000FF\">end<\/font><\/b>\r\nth1<font color=\"#990000\">.<\/font>join\r\n<\/tt><\/pre>\n<pre><tt>select(1, [0], [], [], {0, 349})        = 0 (Timeout)\r\ngettimeofday({1168847486, 478832}, NULL) = 0\r\nselect(1, [0], [], [], {0, 0})          = 0 (Timeout)\r\nwaitpid(25249, 0xbf926810, WNOHANG)     = 0\r\nselect(1, [0], [], [], {0, 0})          = 0 (Timeout)\r\ngettimeofday({1168847486, 479013}, NULL) = 0\r\ngettimeofday({1168847486, 479053}, NULL) = 0\r\nselect(1, [0], [], [], {0, 59959})      = 0 (Timeout)\r\ngettimeofday({1168847486, 538971}, NULL) = 0\r\nselect(1, [0], [], [], {0, 41})         = 0 (Timeout)\r\ngettimeofday({1168847486, 543017}, NULL) = 0\r\nselect(1, [0], [], [], {0, 0})          = 0 (Timeout)\r\nwaitpid(25249, 0xbf926810, WNOHANG)     = 0\r\nselect(1, [0], [], [], {0, 0})          = 0 (Timeout)\r\ngettimeofday({1168847486, 543200}, NULL) = 0\r\ngettimeofday({1168847486, 543240}, NULL) = 0\r\nselect(1, [0], [], [], {0, 59959})      = 0 (Timeout)\r\ngettimeofday({1168847486, 602842}, NULL) = 0\r\nselect(1, [0], [], [], {0, 357})        = 0 (Timeout)\r\ngettimeofday({1168847486, 606842}, NULL) = 0\r\nselect(1, [0], [], [], {0, 0})          = 0 (Timeout)<\/tt><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Stefano Zacchiroli said: To balance this, according to my first read of Ruby&#8217;s threading capability, it&#8217;s my impression that not only at most one thread can execute Ruby code at a time (limitation shared by OCaml, due to the non-distributed nature of mark and sweep garbage collectors), but also a thread blocked on a syscall [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"0","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-227","post","type-post","status-publish","format-standard","hentry","category-planetdebian"],"_links":{"self":[{"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/227","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=227"}],"version-history":[{"count":0,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/227\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lucas-nussbaum.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}