Need document for how porting IO.select(...) in ruby Crystal

IO.select was removed since 2017 by this PR.

But for users come from ruby, it still not easy to porting exists code into Fiber + Channel, there is still no a detailed document for how to do this, some examples in that PR is only touch the most simple user case.

For me, a user use Crystal for half years, still don’t know how to porting following code to Crystal, showing real-life use cases is often not as easy as comments in the PR.

Basically, this is a example read non-blocked from several ios, for differnt io, we may need handle differently, with a timeout settings.

Thread.new do
  timeout = 30

  loop do
   # try to read from io1 and io_list (io_list is a array)
    io = IO.select([io1] + io_list, nil, nil, timeout)

    run_common_logic

    if io # if no timeout
      io.first.each do |reader|
        if reader == io1
          # logic if select on io1
          read_from_io1
          next
        end

        # logic if select on the elements of io_list (io_list may be empty)
        read_from_elements_of_io_list
      end
    end
  end
end

For above code, there is some concerns need to mention:

  1. the io_list will changes when running, that is why in the above code, io_list is in a loop, we have to handle it when porting.

  2. we have to handle the timeout in IO.select(io_list, nil, nil, timeout)

  3. pay attention to there is a if io condition and next, This may be a complicated place.

Any idea? if this code can porting to Crystal correctly, it will be a perfect example for original PR.

Thanks.


BTW: this post is related to another my old post Porting a really Ruby IO.select use case into Crystal created several month ago, there is still no a working solution since that.

2 Likes

Crystal uses libevent for evented I/O, so it’s already non-blocking, and it can eliminate the need for select in some cases. In other cases, I would recommend spawning a reader fiber and a timeout fiber, then having a common Channel in which the fastest (reader or timeout) fiber sends a message, e.g. the timeout fiber sends a Nil, or the reader fiber sends a String.

Could you please give a example? e.g. combined with above context.

I figure you might get more responses if you described the behaviour you’re looking to implement instead of just pasting some code that implements this in Ruby. The code example is decently complex and hard to reason about without context. You’re forcing anyone willing to help you to dig into this code and try to understand what you even want before they can start helping you with doing this in Crystal.
If you explain your problem in prose, that’s much easier. Existing code can certainly be a helpful addition, but as sole source of knowledge, it’s quite a hurdle.

2 Likes

Yes, probably people confusing by the context, thought the key is not regarding tightly the context, I just want to learn the way to turn above IO.select logic into Crystal, maybe following pseudo-code is better?

Thread.new do
  timeout = 30

  loop do
   # try to read from io1 and io_list (io_list is a array)
    io = IO.select([io1] + io_list, nil, nil, timeout)

    run_common_logic

    if io # if no timeout
      io.first.each do |reader|
        if reader == io1
          # logic if select on io1
          read_from_io1
          next
        end

        # logic if select on the elements of io_list (io_list may be empty)
        read_from_elements_of_io_list
      end
    end
  end
end

@straight-shoota , Hi, i update my original post according to my previous reply, is the example code clear enough now?

Basically, this is a example read non-blocked from several ios, we may need handle differently according different IO, with a timeout settings.