[HN Gopher] Show HN: Io_uring for Ruby
       ___________________________________________________________________
        
       Show HN: Io_uring for Ruby
        
       Author : ciconia
       Score  : 89 points
       Date   : 2024-09-09 11:59 UTC (11 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | slashdev wrote:
       | The whole point of IO uring is to be fast by reducing the number
       | of system calls per request.
       | 
       | If you then process your requests in the slowest programming
       | language, you add back at least 100x the overhead.
       | 
       | It doesn't make sense to me.
        
         | carbotaniuman wrote:
         | One way you can think of this is speeding up the "slowest
         | programming language". And removing/reducing blocking calls has
         | benefits for languages like Ruby too.
        
           | faizshah wrote:
           | I found the easiest way to explain it is Ruby/Python/Lua are
           | scripting languages for optimized C code.
        
           | slashdev wrote:
           | A syscall is so fast compared to Ruby code. It really doesn't
           | make much sense to me.
        
         | sliken wrote:
         | The slower the language the bigger the upside.
        
           | slashdev wrote:
           | That's false.
           | 
           | If the difference between IO uring and epoll is 2x, but that
           | was only 5% of the total runtime, the rest being slow Ruby
           | code, then at best you get a 2.5% speed up. Not worth it.
        
         | jcmfernandes wrote:
         | I expected this comment, just not so early in the life of this
         | thread. Moving on... cool stuff!
        
           | adamrezich wrote:
           | It shouldn't have been flagged though--what's up with that?
           | Why would someone, let alone multiple people, flag OP's
           | comment? It's inoffensive, doesn't violate guidelines
           | whatsoever, and in fact asks a question that I'm sure many
           | people (myself included) feel is quite worthy of asking, so
           | we can read peoples' responses to it.
           | 
           | Using flags to shut down entirely reasonable discussion is
           | very lame.
        
             | dgfitz wrote:
             | This whole forum is becoming quite lame. I just haven't
             | found a better one yet.
        
             | FridgeSeal wrote:
             | Probably because it's a fairly tired argument that gets
             | rolled out almost automatically in response to any async-IO
             | or high speed IO work. It's like there's a group that likes
             | to argue that only the cream of the crop spills get to use
             | nice new things, and the rest of us spills be pleased with
             | what we have already. At this point, it's a bit "ok thank
             | you", it don't add much.
        
         | ckolkey wrote:
         | Oh, that meme is old, sorry to say. Here's a nice blog post
         | about ruby outperforming C with the new JIT compiler. Fun times
         | :)
         | 
         | https://railsatscale.com/2023-08-29-ruby-outperforms-c/
        
           | neonsunset wrote:
           | Ruby YJIT is slower by multiple orders of magnitude if we
           | look at more than a single constructed example.
           | 
           | In addition, the blog post measures the cost of avoiding
           | doing the interop, which allows wins as the compiler improves
           | in the case of short-lived calls implemented in a native
           | component.
           | 
           | This, however, is not exclusive to Ruby and statically typed
           | JIT or AOT compiled languages benefit from this to a much
           | higher extent.
           | 
           | https://benchmarksgame-
           | team.pages.debian.net/benchmarksgame/...
        
           | slashdev wrote:
           | In very specific, very limited cases.
           | 
           | I remember when these claims were made for Java twenty years
           | ago. It's still slower than C, most of the time.
           | 
           | Some things don't change.
        
         | yxhuvud wrote:
         | Io uring have several use cases. You describe one, but it also
         | enables things like no blocking file IO, which nothing else
         | provides in a useful manner. Ruby can be slow in certain
         | scenarios, but not slow enough that things like that doesxnt
         | matter.
        
           | slashdev wrote:
           | Well that's true. To do async file IO without that is really
           | just using a thread pool.
           | 
           | Of course, I don't see why that won't perform fine for Ruby.
           | 
           | It's just so slow that optimizing the async IO at the OS
           | level doesn't matter
        
         | ciconia wrote:
         | Just this morning I was benchmarking the example HTTP server I
         | wrote using IOU [0]. The usual caveats notwithstanding, I would
         | say 100K sustained requests per second serving 1024 concurrent
         | connections (on a more-or-less average laptop) is anything but
         | slow...
         | 
         | In fact, the whole idea for this library is to provide a low-
         | level, fast, flexible, asynchronous I/O layer for building Ruby
         | apps and letting Ruby+YJIT optimize the app code, which it
         | actually is getting pretty good at.
         | 
         | If you're open to learning more about where the Ruby runtime is
         | performance-wise, there was a very interesting recent talk [1]
         | about this very subject.
         | 
         | [0] https://github.com/digital-
         | fabric/iou/blob/main/examples/htt... [1]
         | https://www.youtube.com/watch?v=qf5V02QNMnA
        
       | jhyaaasdfw wrote:
       | Would Ruby benefit if we put epoll(7) or io_uring(7) on IO
       | boundaries and then do something like Go or BEAM where we preempt
       | at a certain number of function calls or time? One challenge I
       | see with this approach is calling into C libraries although I
       | don't know how common that is in Ruby ecosystem.
        
         | davexunit wrote:
         | It's pretty common to call into C libraries in Ruby. Many
         | widely used Ruby gems have what are called "native extensions".
         | The approach that I know of to deal with this problem is that
         | captured continuations with C stack frames are marked as non-
         | resumable. Trying to resume such a continuation throws an
         | exception. As the programmer, you'd write your async code in a
         | way that avoids calls to C that call back into Ruby to prevent
         | capturing non-resumable continuations.
        
         | xerxes901 wrote:
         | This is in fact exactly what Ruby's Fibers and the async fiber-
         | scheduler gem do
        
       | blacklite wrote:
       | Is Ruby commonly used in high-performance applications?
        
         | yxhuvud wrote:
         | Dunno, but being able to do nonblocking file io could still be
         | useful, I suppose.
        
         | Asmod4n wrote:
         | its definitely better than just having select in the base
         | installation.
        
         | Tuna-Fish wrote:
         | Ruby is used plenty in the kind of situations where the
         | performance of the program itself is less important that the
         | overhead of IO. This should help quite a lot on such loads.
        
       | yxhuvud wrote:
       | It is interesting to compare the effort required to interact with
       | C libs in Ruby and in Crystal. I wrote
       | https://github.com/yxhuvud/ior a couple of years ago and it is
       | roughly on the same level of abstraction as this lib if I read it
       | correctly. So it also allows a nice comparison between how the
       | API is exposed.
       | 
       | Ior doesn't contain the multishot stuff because it didn't exist
       | when I still added stuff to it, but apart from that it do include
       | a whole lot of ops.
        
       | Lammy wrote:
       | Very cool. Would love to see it be Ractor-safe too, which C
       | extensions are not by default.
       | 
       | https://docs.ruby-lang.org/en/master/extension_rdoc.html#lab...
       | sez:
       | 
       | "Ractor safety around C extensions has the following properties:
       | 
       | -- By default, all C extensions are recognized as Ractor-unsafe.
       | 
       | -- Ractor-unsafe C-methods may only be called from the main
       | Ractor. If invoked by a non-main Ractor, then a
       | Ractor::UnsafeError is raised.
       | 
       | -- If an extension desires to be marked as Ractor-safe the
       | extension should call rb_ext_ractor_safe(true) at the Init_
       | function for the extension, and all defined methods will be
       | marked as Ractor-safe."
       | 
       | I don't know enough about io_uring to know if there would be any
       | thread-safety issues to just declaring it, but here's an example
       | pull request from a few years ago enabling Ractor support on a C
       | extension that had no sharing issues:
       | https://github.com/dearblue/ruby-extattr/pull/1/
        
         | ciconia wrote:
         | Thanks, that should be possible. I'll put it on the project's
         | TODO list :-).
        
       ___________________________________________________________________
       (page generated 2024-09-09 23:00 UTC)