**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 :-)