From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-2.9 required=3.0 tests=AWL,BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_MED,SPF_PASS,T_RP_MATCHES_RCVD shortcircuit=no autolearn=ham autolearn_force=no version=3.4.0 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id 957B61F404 for ; Thu, 25 Jan 2018 01:15:31 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 0308C120B42; Thu, 25 Jan 2018 10:15:30 +0900 (JST) Received: from o1678948x4.outbound-mail.sendgrid.net (o1678948x4.outbound-mail.sendgrid.net [167.89.48.4]) by neon.ruby-lang.org (Postfix) with ESMTPS id B7CAC120B3A for ; Thu, 25 Jan 2018 10:15:27 +0900 (JST) Received: by filter0008p3iad2.sendgrid.net with SMTP id filter0008p3iad2-17300-5A692FAC-2C 2018-01-25 01:15:24.439772641 +0000 UTC Received: from herokuapp.com (ec2-50-19-14-97.compute-1.amazonaws.com [50.19.14.97]) by ismtpd0014p1iad2.sendgrid.net (SG) with ESMTP id Cgusy75LQuCzb84o9lC_Wg Thu, 25 Jan 2018 01:15:24.269 +0000 (UTC) Date: Thu, 25 Jan 2018 01:15:25 +0000 (UTC) From: danieldasilvaferreira@gmail.com To: ruby-core@ruby-lang.org Message-ID: References: Mime-Version: 1.0 X-Redmine-MailingListIntegration-Message-Ids: 60327 X-Redmine-Project: ruby-trunk X-Redmine-Issue-Id: 13618 X-Redmine-Issue-Author: normalperson X-Redmine-Issue-Assignee: normalperson X-Redmine-Sender: dsferreira X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-SG-EID: ync6xU2WACa70kv/Ymy4QrNMhiuLXJG8OTL2vJD1yS6ZAfVK0RxTNdE5oWQs+NxQheFHQFXpbGnNo4 ARDqPe9uWWIPEXFyyltChL/khtk7dHqntxGoX5uJQ+GAd3rssWG0zxrLs4NOHqJ7Ym7cPRA/5cyTtW eZZNB0f0sEBlj0oCB0/11ZNq7ASAK165+tSwkSuQWnOkLNjL1o1FMNr3Bg== X-ML-Name: ruby-core X-Mail-Count: 85088 Subject: [ruby-core:85088] [Ruby trunk Feature#13618] [PATCH] auto fiber schedule for rb_wait_for_single_fd and rb_waitpid X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" Issue #13618 has been updated by dsferreira (Daniel Ferreira). Hi Eric, I've been reading this issue and I'm finding it fascinating. Let me play here the role of the ruby developer that is seeking to understand better the asynchronous ruby capabilities. Every time I read threads(conversations) like this one about the pros and cons of Fibers vs Threads I tend to think: stay away from it. When people like Kochi write comments like this: > "But most (many? some? a few?) of ruby programmer (including me) can not write correct code I believe." or Yusuke Endoh: > "Thread is considered harmful. Casual Rubyists (including I) had better not use it." what these comments make us mere mortals feel? I will speak about me. When I read such a line I tend to step away. So yes, this situation makes me develop single threaded code as much as possible. I rely on libraries to handle asynchronous behaviour for me and specially I rely extensively on the actor model. I doubt I will change my mind unless I start to read that Thread is good to be used or Fiber is good to be used. When I read all this conversation and you mention corner cases that still have problems that is a NO GO for me. IMHO to add yet another Thread like feature it should be "The Killer Feature". The one that we can say to the all community: Hey people use this thing because async is a paradise in ruby land at last. If we don't have this it will be just another Thread, Fiber nightmare for the very few who accept the overhead of dealing with all the "buts". And for the record, I use async libraries but I don't feel confident about them either knowing that ruby core is not reliable in itself. Production code in the enterprise world it is not something to mess around. For me ruby core needs desperately to change this situation so I really hope your work will be the answer for all of this I'm talking about. So yes, if it is it fits in ruby core like a glove IMO. If it is not then we will be much worst because instead of 2 walking deads we will have 3. A 50% increase is a lot in this domain. Turns things into a joke. So, can you please explain us what peace of mind will we gain with this new "light thread" in our everyday work? Thank you very much and keep up the excellent work. I appreciate specially the care you have in passing across your knowledge on the subject. Really helpful and insightful. Note: Your last two messages are not part of the issue in redmine. I hope my message will be there! It seems mine did came in as well. I'm copy pasting it. ---------------------------------------- Feature #13618: [PATCH] auto fiber schedule for rb_wait_for_single_fd and rb_waitpid https://bugs.ruby-lang.org/issues/13618#change-69801 * Author: normalperson (Eric Wong) * Status: Assigned * Priority: Normal * Assignee: normalperson (Eric Wong) * Target version: ---------------------------------------- ``` auto fiber schedule for rb_wait_for_single_fd and rb_waitpid Implement automatic Fiber yield and resume when running rb_wait_for_single_fd and rb_waitpid. The Ruby API changes for Fiber are named after existing Thread methods. main Ruby API: Fiber#start -> enable auto-scheduling and run Fiber until it automatically yields (due to EAGAIN/EWOULDBLOCK) The following behave like their Thread counterparts: Fiber.start - Fiber.new + Fiber#start (prelude.rb) Fiber#join - run internal scheduler until Fiber is terminated Fiber#value - ditto Fiber#run - like Fiber#start (prelude.rb) Right now, it takes over rb_wait_for_single_fd() and rb_waitpid() function if the running Fiber is auto-enabled (cont.c::rb_fiber_auto_sched_p) Changes to existing functions are minimal. New files (all new structs and relations should be documented): iom.h - internal API for the rest of RubyVM (incomplete?) iom_internal.h - internal header for iom_(select|epoll|kqueue).h iom_epoll.h - epoll-specific pieces iom_kqueue.h - kqueue-specific pieces iom_select.h - select-specific pieces iom_pingable_common.h - common code for iom_(epoll|kqueue).h iom_common.h - common footer for iom_(select|epoll|kqueue).h Changes to existing data structures: rb_thread_t.afrunq - list of fibers to auto-resume rb_vm_t.iom - Ruby I/O Manager (rb_iom_t) :) Besides rb_iom_t, all the new structs are stack-only and relies extensively on ccan/list for branch-less, O(1) insert/delete. As usual, understanding the data structures first should help you understand the code. Right now, I reuse some static functions in thread.c, so thread.c includes iom_(select|epoll|kqueue).h TODO: Hijack other blocking functions (IO.select, ...) I am using "double" for timeout since it is more convenient for arithmetic like parts of thread.c. Most platforms have good FP, I think. Also, all "blocking" functions (rb_iom_wait*) will have timeout support. ./configure gains a new --with-iom=(select|epoll|kqueue) switch libkqueue: libkqueue support is incomplete; corner cases are not handled well: 1) multiple fibers waiting on the same FD 2) waiting for both read and write events on the same FD Bugfixes to libkqueue may be necessary to support all corner cases. Supporting these corner cases for native kqueue was challenging, even. See comments on iom_kqueue.h and iom_epoll.h for nuances. Limitations Test script I used to download a file from my server: ----8<--- require 'net/http' require 'uri' require 'digest/sha1' require 'fiber' url = 'http://80x24.org/git-i-forgot-to-pack/objects/pack/pack-97b25a76c03b489d4cbbd85b12d0e1ad28717e55.idx' uri = URI(url) use_ssl = "https" == uri.scheme fibs = 10.times.map do Fiber.start do cur = Fiber.current.object_id # XXX getaddrinfo() and connect() are blocking # XXX resolv/replace + connect_nonblock Net::HTTP.start(uri.host, uri.port, use_ssl: use_ssl) do |http| req = Net::HTTP::Get.new(uri) http.request(req) do |res| dig = Digest::SHA1.new res.read_body do |buf| dig.update(buf) #warn "#{cur} #{buf.bytesize}\n" end warn "#{cur} #{dig.hexdigest}\n" end end warn "done\n" :done end end warn "joining #{Time.now}\n" fibs[-1].join(4) warn "joined #{Time.now}\n" all = fibs.dup warn "1 joined, wait for the rest\n" until fibs.empty? fibs.each(&:join) fibs.keep_if(&:alive?) warn fibs.inspect end p all.map(&:value) Fiber.new do puts 'HI' end.run.join ``` ---Files-------------------------------- 0001-auto-fiber-schedule-for-rb_wait_for_single_fd-and-rb.patch (82.8 KB) -- https://bugs.ruby-lang.org/