dabeaz / curio

Good Curio!
Other
4.01k stars 240 forks source link

Curio equivalent of asyncio Future #272

Closed hniksic closed 4 years ago

hniksic commented 5 years ago

Occasionally I find asyncio.Future useful as a synchronization primitive in its own right, and I'm wondering if there is a corresponding construct in curio. Please note that I'm aware that curio is not built around futures the way asyncio is - this issue is specifically about using a future as a tool to transfer data between different coroutines. Let me illustrate that with two examples.

Example 1: broadcasting messages to clients running in separate coroutines.

Code in this SO answer periodically broadcasts data to multiple running coroutines. Each of the coroutines await on a shared Future, and the broadcaster uses set_result() to send them all a message. The broadcaster immediately sets the variable to a new shared future, which results in the coroutines that receive the message immediately start waiting for the new one.

Example 2: Synchronizing between a single producer and multiple consumers.

Another SO answer contains a slightly more involved example. It does something that looks simple: runs two aggregate functions (coroutines) in parallel over the same iterator without buffering. The code needs to transmit each produced value to multiple consumers and relies on a similar technique, using a Future as a lightweight broadcasting medium. The future is especially convenient because it already carries a payload value (which can in the general case also be an exception) but is otherwise really lightweight compared to primitives inspired by threading.

The closest curio alternative I've found is to use an Event and simply attach a value to it. However, doing for the second example results in an execution time 1.2x slower than asyncio - reproducible example attached. (BTW, greenlet's explicit switching appears an order of magnitude faster than either - see the above SO answer for code.)

Would curio actually benefit from a future-like synchronization device, or am I doing something completely wrong?

dabeaz commented 5 years ago

There was a contribution of a Promise class that can be found in curio/promise.py. However, it's not documented and I've been pondering what to do with it long-term.

I had considered the idea of making a Future for Curio, but possibly along the same line of thinking as the UniversalEvent and UniversalQueue classes--meaning that I'd try to make it something that could be used from threads or async in any combination.

Short answer: I'd consider something like this. I'll take a look at the attached example as well.

agronholm commented 5 years ago

Yury Selivanov has gone on record saying that Futures are going away in asyncio.

dabeaz commented 5 years ago

So far as I know, Yury's comment pertains to the use of Futures in the internal implementation of asyncio. This bug pertains to supporting a Future/Promise as a user-level synchronization primitive between Curio tasks, much like an Event object. I'm open to that.

hniksic commented 5 years ago

@agronholm I didn't know that, do you have a link with more information? @dabeaz explained why this is not directly relevant to this issue, but it's still an interesting development.

CreatCodeBuild commented 5 years ago

Would a synchronization queue a cleaner programming model than futures/promises? If one programs with concurrent tasks(threads or async tasks...) and synchronization queues only, then one can achieve concurrency with pure synchronized API.

agronholm commented 5 years ago

Do you have an example implementation of such a thing somewhere?

Kentzo commented 5 years ago

Apple’s Grand Central Dispatch (often abbreviated as GCD or libdispatch) is built around a concept of serial and concurrent queues.

Best Regards Ilya Kulakov

On Sep 3, 2018, at 11:50 AM, Alex Grönholm notifications@github.com wrote:

Do you have an example implementation of such a thing somewhere?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.