<story><title>Goroutines, Nonblocking I/O, and Memory Usage</title><url>https://eklitzke.org/goroutines-nonblocking-io-and-memory-usage</url></story><parent_chain></parent_chain><comment><author>atombender</author><text>It always struck me as odd that Go has select{}, but no way to select on a file descriptor such a socket. There&amp;#x27;s literally no way to poll a file descriptor: You have to read from it, and deal with the result.&lt;p&gt;That also means reads aren&amp;#x27;t interruptible (unless you count closing the descriptor as interrupting, which is a blunt hammer indeed). AFAIK the only way to do this is to set SetReadDeadline() on the connection to a smallish value, then let the interrupter block on a channel that&amp;#x27;s invoked when the deadline is reached.&lt;p&gt;Go&amp;#x27;s concurrency model is pretty friendly, but it&amp;#x27;s also unfriendly in many surprising ways. (Don&amp;#x27;t get me started on the whole nil channel thing, or the problem of channel closure&amp;#x2F;ownership, or channel performance overall.) It doesn&amp;#x27;t surprise me the least (while it did surprise the Go team) that Go fell flat among the C&amp;#x2F;C++ system programmer demographic.&lt;p&gt;Anyone want to chip in about how Rust, Swift and Nim compare here (regarding the article)?</text></comment>
<story><title>Goroutines, Nonblocking I/O, and Memory Usage</title><url>https://eklitzke.org/goroutines-nonblocking-io-and-memory-usage</url></story><parent_chain></parent_chain><comment><author>zimbatm</author><text>This would be solved if the &amp;quot;select&amp;quot; keyword was also working on I&amp;#x2F;O objects. It could gain special io.ReadReady and io.WriteReady channels that return a boolean.&lt;p&gt;This would also simplify most of the code that tries to pull events from different sources, including I&amp;#x2F;O. Right now each I&amp;#x2F;O needs to be extracted in it&amp;#x27;s own goroutine (adding error handling makes it worse):&lt;p&gt;&lt;pre&gt;&lt;code&gt;    fromIO := make(chan []byte)
    go func() {
       for {
          buf := myPool.Get()
          myIO.Read(buf)
          fromIO &amp;lt;- buf
       }
    }()

    for {
      select {
      case a := &amp;lt;-fromIO:
        &amp;#x2F;&amp;#x2F; do one thing
      case b := &amp;lt;-fromOtherChan:
        &amp;#x2F;&amp;#x2F; something else
      }
    }
&lt;/code&gt;&lt;/pre&gt;
After the change:&lt;p&gt;&lt;pre&gt;&lt;code&gt;    for {
      select {
      case &amp;lt;-myIO.ReadReady:
        buf := myPool.Get()
        myIO.Read(a)
      case b := &amp;lt;-myOtherChan:
        &amp;#x2F;&amp;#x2F; ...
     }&lt;/code&gt;&lt;/pre&gt;</text></comment>