Skip to content

Add settable promise #98

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed

Add settable promise #98

wants to merge 2 commits into from

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