Skip to content

Conversation

@art-w
Copy link
Contributor

@art-w art-w commented Nov 28, 2022

Another question mark, I'm not sure that this PR fits with domainslib general design.

I was playing with a lockfree MPMC queue and noticed that it would work well as a substitute for domainslib's Chan. The only catch is "what to do when the queue is empty and we want to pop?", because I would prefer to suspend only the current task, and not lock the current domain entirely as it could go do other stuff in the mean time. The simplest synchronization primitive I could think of is a mutable promise, such that the pop task can await it and the matching push will resolve it.

  • I didn't actually replace Chan just yet, because it is currently independent from Task and either module can be used without the other -- is this intended or would it make sense to specialize Chan to maximize performances when used with tasks?

A small benchmark to demonstrate that the proposed API yields more stable performances than the alternatives:

num_domains:      1        2        3        4        5        6        7        8   
  Mpmc_pool:     57.88    63.12    52.85    61.69    51.93    52.57    64.47   394.69  <-- uses the new Task.promise
 Mpmc_retry:     60.60    71.01    83.98   110.93   202.37   155.83   192.37  1650.86  <-- uses spinlock, same impl as above
       Chan:    178.39   259.55   349.11   415.49   417.29   625.99   634.01  1221.45  <-- Domainslib.Chan

(num_domains is actually "+ 1" hence the drop at 9 domains :/)

(cc @bartoszmodelski in case you have some thoughts on this! ^^)

| Empty ->
let promise, set_promise = Domainslib.Task.promise () in
if Atomic.compare_and_set cell Empty (Await set_promise)
then Some (Domainslib.Task.await pool promise)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The three lines above are the fancy bit! When pop fails to obtain a value, it pushes a function onto the queue that will be called by the matching push to unlock the task :)

@kayceesrk
Copy link
Contributor

Any blocking parallel data structures such as promises should be included in Saturn with concurrency libraries utilising such blocking data structures should be using domain-local await. CC @Sudha247 @polytypic.

@kayceesrk kayceesrk closed this Jul 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants