From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-4.1 required=3.0 tests=AWL,BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.1 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id C1E7D208EB for ; Wed, 8 Aug 2018 08:49:08 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id EB5DC120CBC; Wed, 8 Aug 2018 17:49:06 +0900 (JST) Received: from dcvr.yhbt.net (dcvr.yhbt.net [64.71.152.64]) by neon.ruby-lang.org (Postfix) with ESMTPS id 639DD120CAC for ; Wed, 8 Aug 2018 17:49:01 +0900 (JST) Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 5FE4F208EB; Wed, 8 Aug 2018 08:48:59 +0000 (UTC) Date: Wed, 8 Aug 2018 08:48:59 +0000 From: Eric Wong To: ruby-core@ruby-lang.org Message-ID: <20180808084859.6feyevl3skswqn6k@dcvr> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-ML-Name: ruby-core X-Mail-Count: 88350 Subject: [ruby-core:88350] Re: [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" samuel@oriontransfer.net wrote: > I've been playing around with my gem async and I've come to > the conclusion that it is a great way to do IO, but it does > have some cases that need to be considered carefully. Right. > In particular, when handling HTTP/2 with multiple streams, > it's tricky to get good performance because utilising multiple > threads is basically impossible (and this applies to Ruby in > general). With HTTP/1, multiple "streams" could be easily > multiplexed across multiple processes easily. I'm no expert on HTTP/2, but I don't believe HTTP/2 was built for high-throughput in mind. By "high-throughput", I mean capable of maxing out the physical network or storage. At least, multiplexing multiple streams over a single TCP connection doesn't make any sense as a way to improve throughput. Rather, HTTP/2 was meant to reduce latency by avoiding TCP connection setup overhead, and maybe avoiding slow-start-after-idle (by having less idle time). In other words, HTTP/2 aims to make better use of a heavy-in-memory-but-often-idle resource. > What this means is that a single HTTP/2 connection, even with > multiple streams, is limited to a single thread with the > fiver-based/green-thread design. I don't see that is a big deal because of what I wrote above. > I actually see two sids to this: It limits bad connections to > a single thread, which is actually a feature in some ways. On > the other hand, you can't completely depend on multiplexing > HTTP/2 streams to improve performance. Right. > On the other hand, any green-thread based design is probably > going to suffer from this problem, unless a work pool is used > for actually generating responses. In the case of > `async-http`, it exposes streaming requests and responses, so > this isn't very easy to achieve. Exactly. As I've been say all aalong: use different concurrency primitives for different things. fork (or Guilds) for CPU/memory-bound processing; green threads and/or nonblocking I/O for low-throughput transfers (virtually all public Internet stuff), native Threads for high-throughput transfers (local/LAN/LFN). So you could use a green thread to coordinate work to the work pool (forked processes), and still use a green thread to serialize the low-throughput response back to the client. This is also why it's desirable (but not a priority) to be able to migrate green-threads to different Threads/Guilds for load balancing. Different stages of an application response will shift from being CPU/memory-bound to low-throughput trickles. > I've also been thinking about timeouts. > > I've been thinking about adding a general timeout to all > socket operations. The user can set some global default, (or > even set it to nil). When the user calls `io.read` or > `io.write` there is an implicit timeout. I'm not sure if this > is a good approach, but I don't think it's stupid, since `io` > operations are naturally temporal so some kind of default > temporal limit makes sense. Timeout-in-VM [Feature #14859] will be most optimized for apps using the same timeout all around. I'm not sure it's necessary to add a new API for this if we already have what's in timeout.rb Also, adding a timeout arg to every single io.read/io.write call is going to be worse for performance, because every timeout use requires arming/disarming a timer. Whereas a single "Timeout.timeout" call only arms/disarms the timer once.