**Preface to the Preface**

I have been reading into async, and Nim's implementation of async. @Dom96's 
book is amazing on this subject btw. much cudos... I have also been going down 
the rabbit hole of reading Joe Duffy's amazing blog and the Midori project 
([http://joeduffyblog.com/2015/11/19/asynchronous-everything/](http://joeduffyblog.com/2015/11/19/asynchronous-everything/))

**Preface**

Async and threads _can_ go together like peanut butter and jelly, but sadly, 
the Nim implementations are currently incomplete.

Specifically: We have two communication primitives for Threads today

  * Channels
  * FlowVar



But neither one has async support yet. This is sad.

**On to the Idea already**

My idea is to attempt to "kill two birds with one stone" so to speak.

1\. Implement the async api for Channels.

Nothing special here. The polling just needs to be integrated into 
asyncDispatch, and the appropriate async apis exposed for channels.

2\. Use the new _Async Channel_ api to implement FlowVar

A FlowVar is essentially a Future that is specialized to wait for another 
thread. A Channel is a way to send and receive values across threads. In other 
words, a FlowVar is an async channel that is single use (one send and receive).

A FlowVar can essentially become a template / macro that expands to:

  * create an async channel
  * spawn a thread with a function that takes a ptr to the channel
  * await the channel
  * The other thread does it's business, sends the result through the channel, 
and dies (or returns to the threadPool). consideration must be made for error 
conditions of course.
  * close the channel



**Why I like this idea**

  * Code reuse:
    * FlowVar seems like just a special case of a channel afaict
    * Multi-threading is hard, this lets us concentrate on a single thread 
communication primitive (channels), to get bug fixes and perf improvements.
  * Separation of concerns:
    * This separates FlowVar from the Threadpool module, which, let's face it, 
is buggy and has bad perf issues at the moment. This lets us have parallsim in 
our async without having to wait for Threadpools to get better, and still have 
a nice api.
    * Don't get me wrong, I want a better Threadpool, but that seems like a 
much larger project.
      * This is a stepping stone project that lets us have good async -> 
parallel api's much sooner.
  * Nim doesn't have a good story for Threads for 1.0 right now.
    * This is one of the main reasons @araq started working on _newruntime_. 
But afaik, _newruntime_ is going to be behind a flag and not the default for 1.0
    * A vocal portion of the community has not bought into _newruntime_ , or is 
keeping the GC for other reasons, but everyone has accepted async.
      * These people deserve good async -> parallel apis too. This gives them 
_something_ to work with.
    * Async Channels gives us a reasonable and safe story for threaded 
communication that is 1.0 GC compatible, and transparently gets better with 
_newruntime_ (see below)



**Notes**

  * Optimizations
    * It is not strictly necessary, but it may be a good idea to implement more 
async friendly versions of locks and monitors that don't actually put the 
thread to sleep, but instead simply yield to the event loop. Maybe based on 
asynctools from @cheatface 
([https://github.com/cheatfate/asynctools/blob/master/asynctools/asyncsync.nim](https://github.com/cheatfate/asynctools/blob/master/asynctools/asyncsync.nim))
    * The Channel implementation is pretty naive atm. A way more efficient 
implementation would be a lock free single reader single writer ring buffer 
queue using atomics. This isn't strictly necessary but would be nice. We could 
always fall back to the naive locking implementation on platforms where atomics 
aren't available.
    * In Fact, the multi reader version isn't _that_ much more complicated than 
the single reader version, and would allow "broadcast channels", which is kind 
of interesting, but also pie in the sky feature creep :-P
  * What about \--newruntime, isn't that supposed to make threads in Nim 
amazing?
    * Yes, but for different reasons. Newruntime is about memory, this is about 
communication. They are orthogonal concepts.
    * Channels are still a very useful tool for coordinating and communicating 
across threads. Go uses them for a reason.
    * Newruntime will let us optimize Channels transparently
      * For the _newruntime_ version, Instead of copying the data that is sent 
over the channel, the channel just changes the owner of the data.
      * If you use channels, the newruntime version will just be magically 
faster because of less copying.



**Questions**

  * Is FlowVar really just a special case of an async Channel?
    * This is my primary assumption, but maybe I'm wrong. I would love for 
somebody to poke holes in this.
  * asyncStreams
    * Even more experimental, less tested, and less documented than Channels or 
FlowVar
    * Also seems like a special case of an async Channel (or at least can be 
implemented using asyncChannels)
    * Might be a good candidate for removal from the stdlib or re-architecting 
in light of this?



What does the community think about this?

Thanks in advance for any feedback and questions :-)

Reply via email to