I didn't use ARC because when I started evaluating multithreading options (July 
2019) and implementing Weave (November 2019) it was not ready at all.

Now at the moment, I'm ready to run my batteries of tests on arc: 
[https://github.com/mratsim/weave/blob/33a446ca/weave.nimble#L99-L167](https://github.com/mratsim/weave/blob/33a446ca/weave.nimble#L99-L167)
 But I need to be able to at least have custom channels working: 
[https://github.com/nim-lang/Nim/issues/13936](https://github.com/nim-lang/Nim/issues/13936)

I do provide already the primitives necessary to have `awaitable` (in the async 
sens) Weave jobs via `isReady`, you only need to replace the `sleep()` by 
`poll()` here in my own 
[waitFor](https://github.com/mratsim/weave/blob/33a446ca4ac6294e664d26693702e3eb1d9af326/weave/datatypes/flowvars.nim#L234-L249):
 
    
    
    proc waitFor*[T](p: Pending[T]): T {.inline.} =
      ## Wait for a pending value
      ## This blocks the thread until the value is ready
      ## and then returns it.
      preCondition: onSubmitterThread
      
      var backoff = 1
      while not p.isReady:
        sleep(backoff)
        backoff *= 2
        if backoff > 16:
          backoff = 16
      
      let ok = p.fv.tryComplete(result)
      ascertain: ok
      cleanup(p.fv)
    
    
    Run

See writeup/RFC: 
[https://github.com/mratsim/weave/issues/132](https://github.com/mratsim/weave/issues/132)

The main issue right now that the GC cannot solve is if we ever want to 
implement an `executor` API/concept or at least common `Task` abstraction to 
could be dispatch on either:

  * Async executors (async dispatch/chronos/libuv)
  * Parallel executors (Nim threadpool / Weave)
  * An simple executor for blocking tasks like `readline()` because just as you 
shouldn't block asyncdispatch, you shouldn't block Weave with non-computational 
tasks.



The simple reason why is that tasks in a parallel runtime are threadsafe 
closures + metadata, and the GC being thread-local prevents closures from being 
sent across threads.

This brings us to why we would want a common Task abstraction

To be honest I'm not sure, but I'm sure we would want a threadsafe async 
executor, potentially with task stealing as well, it's not even hard to write 
(at least the task stealing side, ~2k lines):

  * 
[https://github.com/stjepang/async-task](https://github.com/stjepang/async-task)
  * [https://github.com/stjepang/smol](https://github.com/stjepang/smol)



but this would require threadsafe closures.

i.e. threadsafe /sendable closures are the core primitive that ARC brings us. 
It also gives us `owned` and destructors give use sink which we can use to 
enforce ownership when we send tasks across threads. This significantly reduce 
the need of Atomic Refcounting schemes as we can just deep-copy the pointers 
instead.

For example, we need to enforce ownership of futures. (Hence why I hope that 
when a proc is tagged with `sink` parameters it also prevents the caller from 
ever reusing that variable again)

Reply via email to