Proposal: Coroutines & suspendable functions #3054
Replies: 16 comments
-
A runtime support for coroutines would be much nicer. Here you just subscribe to the same |
Beta Was this translation helpful? Give feedback.
-
@bilal-fazlani |
Beta Was this translation helpful? Give feedback.
-
Just a note: you seem to be treating |
Beta Was this translation helpful? Give feedback.
-
@canton7 about async yes you are right. But writing async functions also forces you to change the return type to Task. If I dont await, and just call the method, the call returns before task is complete and all I have is just a task. Suspendable functions are similar to async functions except they have concrete return types and return only when they done doing their tasks |
Beta Was this translation helpful? Give feedback.
-
@bilal-fazlani |
Beta Was this translation helpful? Give feedback.
-
It's unclear whether you're proposing compiler or runtime changes. You say that suspendable methods would return concrete types, not something like |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt the same way we call async functions from non async functions. For example, when the main of a cli app is not marked async, you cant await. So you block that function call because otherwise cli app would exit before task returned from function is completed. Kotlin provides many helper utils for these scenarios. |
Beta Was this translation helpful? Give feedback.
-
You're thinking about it backwards. The central part is |
Beta Was this translation helpful? Give feedback.
-
Also note that, afair, Kotlin's coroutines are implemented in a way which is not dissimilar to C#. So Kotlin's Given this, I think your proposal boils down to introducing a mechanism which is the same as
Is that correct? |
Beta Was this translation helpful? Give feedback.
-
That sounds right. @canton7 |
Beta Was this translation helpful? Give feedback.
-
So the only "advantages" are:
Is that correct? However, you would of course still need to fall back to the current ecosystem when creating a Presumably you would still be able to call |
Beta Was this translation helpful? Give feedback.
-
Yes
Yes
When working with suspendable functions kotlin has ways to provide context. https://link.medium.com/XpXwby9vJ2 . This blog is by the author of coroutines. We can think of how this can be adopted for our use cases. Since Task return type will not be exposed directly to user when using suspendable function, we might need a similar mechanism |
Beta Was this translation helpful? Give feedback.
-
This is a design choice that the c# team made when designing and await. They considered your design, and ultimately decided not to go with it. Like all choices it has trade offs, and c# is going to have to live with those trade offs forever. However introducing another feature with exactly the same features, but different style choices is not a good idea. It just leads to confusion, more stuff to learn, inconsistency in the ecosystem, and doesn't provide any significant value. In short, this is essentially a stylistic question. The decisions been made. We're going to have to live with it. |
Beta Was this translation helpful? Give feedback.
-
I think for a general-purpose coroutine feature to get off of the ground you'd have to demonstrate use cases outside of iterators and async methods. Those cases are covered, even if you'd prefer a different syntax. I like general purpose coroutines. They add a lot of power to a language. It has been expressed more than once that members of the team wish that there were runtime primitives that would support coroutines, and that iterators and async methods were built on top of them rather than requiring the extent of compiler machinery that they do today. If the runtime were to add said primitives then I think that there's a chance that they'd be exposed in the language. Otherwise I doubt that the team would consider adding them. |
Beta Was this translation helpful? Give feedback.
-
I'll also note that general-purpose coroutines also suffer in that they're generally only resumable from the consumer. Iterator coroutines in C# can be resumed in two ways, one to try to advance to the next element and one to close the iterator. The latter allows for iterators that wrap emitting sequences from a disposable resource with cleanup logic in a |
Beta Was this translation helpful? Give feedback.
-
What you want actually not a Which is no point. We are more flexible to use Admittedly it was flawed of C# that we can't use |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Introduction
Hello everyone,
After seeing Kotlin coroutines and suspendable functions in action, I feel that the Kotlin has nailed concurrency for modern async programming. This is a proposal to bring in coroutines and suspendable functions in C#. I am not proposing coroutines as a replacement of anything but as an addition to concurrency model of c#.
Context
Today, our current basic C# syntax to deal with asynchronous Tasks are
async
&await
. Without Tasks and Async/Wait, we would be unnecessarily blocking threads or going into callback hell. Async Tasks allowed us to write Concurrent code, which “appears” to be “sequential”. It removed the callback noise. When someone looked at the code, it allowed them see the “What” directly without having to go through the mental struggle of separating the “whats” and “hows”.Today when we call an async method which returns a
Task
, we have two options (besides blocking):Foo()
,Bar()
andBla()
sequentially, then the most common way to achieve this would be to await every call.await
for those tasks concurrently with utilities such asTask.WhenAll
I bring thing this example to make two distinctions -
sequential async code
andparallel async code
. I will try to address how suspendable can help makesequential async code
better.What
This is what I am proposing. If you look at this method, it has very minimal information about how it’s going execute the code. All you see here is what is going to be executed. methods
Foo
,Bar
&Bla
are also markedsuspend
the same wayMyMethod
is.Why
My proposal is based on my understanding that our modern async code has more of
sequential async code
thanparallel async code
. And I believe we should take** one more step** to make it look more “sequential” (more natural IMO).In today’s world, this won’t compile
Because the return type of
Foo()
is not string butTask<string>
. In order to make any use of that string, you will have to be more explicit and verbose and say that you want to wait untilFoo()
has finished. Like this:This only makes sense if you want to do something else if you want to perform other operations while
Foo()
is in progress. There are so many situations where you just can’t and don’t want to move ahead untilFoo
is complete but since the default behaviour is to just return immediately without completing the intent of method, developers have to write the additionalawait
every time they want to change the default behaviour.👉 We have to opt-in for sequential behaviour even though the sequential behaviour seems more natural fit for many cases.
Intent vs Implementation
What is the intent of this method? It’s pretty clear, isn’t it? The intent of this method is to take some numbers and put them in the database. But this is synchronous method and blocks the thread. How do we write a nice asynchronous version of the same method so that we don’t waste resources. Does the below code serve purpose?
Nice. This is async. But is the intent same or different now? When you simply call this method
Will it do the same thing as
DumpNumbersIntoDatabase
but asynchronously? I don’t think so. It will just *begin to execute the intent * and return you aTask
on which you can wait asynchronously or query periodically to check if it’s complete. But that’s not what we wanted. We wanted to create a method which takes some numbers and stores them in database without blocking the thread.Let’s try the good old callback mechanism
Does this capture the intent? Nope. It also just begins to execute the intent and returns nothing.
👉 Is there a way in C# (or dotnet?) where I can express this intent?
This mechanism is useful when you want to move on from execution point but not so much when I just wanted to do some stuff asynchronously.
How do suspendable functions help?
Suspendable functions does come with some similar restrictions that async functions come with. You can call another suspendable function from an existing suspendable function. But they help in two ways
So no more additional step of awaiting. You code is more business logic and less async mechanism
Question: How do I write parallel async code?
Answer: The same way you did earlier
Beta Was this translation helpful? Give feedback.
All reactions