share
Stack OverflowWhat is a coroutine?
[+304] [14] yesraaj
[2009-02-16 15:36:43]
[ concurrency language-agnostic terminology coroutine ]
[ https://stackoverflow.com/questions/553704/what-is-a-coroutine ]

What is a coroutine? How are they related to concurrency?

(3) Concurrent code does not have necessarily have to run in "parallel" (let's not introduce new terms). - lucid_dreamer
(3) I've written one coroutine library with standard C, supporting select/poll/eplll/kqueue/iocp/Win GUI messages for Linux, BSD and Windows. It's a open-source project in github.com/acl-dev/libfiber. Advice will be wellcome. - ShuXin Zheng
I can imagine this question will be downvoted if it's asked at this current era. Not sure why is there such vast difference of community perception as compared to before? - tnkh
(2) a coroutine is a function that can suspend its execution before reaching return, and it can indirectly pass control to another coroutine for some time. - hassanzadeh.sd
Jesus. All answers here are patently wrong. - Konrad Rudolph
@KonradRudolph, can you please explain what a coroutine is? The most upvoted answer does not go with wikipedia explanation. - reyad
@reyad In a nutshell, Wikipedia is right, the answers are wrong (in particular, coroutines implement concurrency, in direct contradiction to what multiple answers falsely claim). The answer by “Izana” that was written after my comment is correct. yield generators in Python are an example of coroutines. async declares are fully fledged coroutine. - Konrad Rudolph
I have just completed the whole wikipedia article on coroutines and understood it properly. I still have one confusion though, it's actually on implementation level. Can coroutine exists on two seperate threads and still call each other(i.e. switch between them)? coroutine supposed to be lightweight, according to wikipedia switching between coroutines need not involve any system calls or any blocking calls whatsoever. Can you pls clear it for me? Cause, goroutine creates threads. Is it same for lua? - reyad
[+184] [2009-02-16 15:46:32] user21714

Coroutines and concurrency are largely orthogonal. Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning.

The 'yield' statement in Python is a good example. It creates a coroutine. When the 'yield ' is encountered the current state of the function is saved and control is returned to the calling function. The calling function can then transfer execution back to the yielding function and its state will be restored to the point where the 'yield' was encountered and execution will continue.


(23) What is the difference between calling a function directly and yielding from a coroutine with wrapping this function into this coroutine? - Meng Zhang
(3) It might be better to explain that these two concepts are not really 'orthogonal' in this context then. You can definitely draw how the two concepts are similar to each other. The idea of passing control between two or more things is very similar. - steviesh
(11) Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning. <-- This is concurrency. The word you are looking for is parallelism. - Adam Arold
(1) @steviejay orthogonal = Not similar to each other? - tonix
@user21714 I thought that Python's yield was a language construct to implement generators, which are essentially a subset of coroutines. If we talk about "pure" coroutines, then the control is not returned to the calling function, but to another coroutine. What can you say about that? - tonix
(4) @tonix I was told that orthogonal means "independent of each other". - Rick
1
[+108] [2018-12-07 05:21:20] mr1031011

I find most of the answers too technical even though it is a technical question. I had a hard time trying to understand the coroutine process. I kind of get it but then I don't get it at the same time.

I found this answer here very helpful:

https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9

To quote from Idan Arye:

To build on your story, I'd put it something like this:

You start watching the cartoon, but it's the intro. Instead of watching the intro you switch to the game and enter the online lobby - but it needs 3 players and only you and your sister are in it. Instead of waiting for another player to join you switch to your homework, and answer the first question. The second question has a link to a YouTube video you need to watch. You open it - and it starts loading. Instead of waiting for it to load, you switch back to the cartoon. The intro is over, so you can watch. Now there are commercials - but meanwhile a third player has joined so you switch to the game And so on...

The idea is that you don't just switch the tasks really fast to make it look like you are doing everything at once. You utilize the time you are waiting for something to happen(IO) to do other things that do require your direct attention.

Definitely check the link, there are much more that I cannot quote everything.


(11) Very simple and straight-forward illustration. +1 for this. - Taslim Oseni
(2) great illustration. I built a similar story - with standing in line waiting to collect a package. but for today, yours is much more realistic, who stands in line when there are door2door deliveries? Lol - apolak
(1) That's awesome explanation. From quote itself, it is super clear. - Farruh Habibullaev
This makes all the other explanations here make much more sense. Code is the set of CPU instructions. Coroutines allow instructions to continue while waiting for tasks outside the CPU to finish - wamster
I found that i cannot understand this quote here but understand the "technical" descriptions. I think this example just makes people feel like they understand it without actually understanding it. - Artur Jackson
Explanation is great but what are those things you are waiting for? Are those resources that you wait to be freed so you other task can resume or not? This is very abstract analogy. If those "things" are resources you are waiting to be free what could be an example for that? - Farid
But isn't I/O blocking for the most part? - user129393192
2
[+95] [2015-07-01 03:11:11] Nan Xiao

From Programming in Lua [1], "Coroutines" section:

A coroutine is similar to a thread (in the sense of multithreading): it is a line of execution, with its own stack, its own local variables, and its own instruction pointer; but it shares global variables and mostly anything else with other coroutines. The main difference between threads and coroutines is that, conceptually (or literally, in a multiprocessor machine), a program with threads runs several threads in parallel. Coroutines, on the other hand, are collaborative: at any given time, a program with coroutines is running only one of its coroutines, and this running coroutine suspends its execution only when it explicitly requests to be suspended.

So the point is: Coroutines are "collaborative". Even in multi-core system, there is only one coroutine running at any given time (but multiple threads can run in parallel). There is non-preemptive between coroutines, the running coroutine must relinquish the execution explicitly.

For "concurrency", you can refer Rob Pike's slide [2]:

Concurrency is the composition of independently executing computations.

So during coroutine A's execution, it passes control to coroutine B. Then after some time, the coroutine B passes control back to coroutine A. Since there is dependency between coroutines, and they must run in tandem, so the two coroutines are not concurrency.

[1] http://feistyduck.myshopify.com/products/programming-in-lua
[2] http://talks.golang.org/2012/concurrency.slide#6

(1) I was loving this answer until I got to the last sentence. What does it mean? Did you misspell "concurrency"? If so, that conclusion doesn't seem to match the definition provided. Or is that meant to be a new word "concurreny"? What does that word mean? - Erick G. Hagstrom
@ErickG.Hagstrom: Sorry, I misspelled concurrency. Why do you think the conclusion doesn't seem to match the definition provided? - Nan Xiao
(8) Coroutines do not execute independently. They take turns, each waiting for the other to do some part of the work. They actively coordinate with each other. That's the opposite of Rob Pikes definition of concurrency. - Erick G. Hagstrom
(2) @ErickG.Hagstrom: Although they don't execute independently, the logic of every coroutine can be independent, right? If it is right, it is just like an un-preemptive OS running on one-core CPU, one process must relinquish CPU to let other tasks run. - Nan Xiao
(7) There's a difference between relinquishing the CPU to let some other task run, and telling some specific other process that it's time to execute. Coroutines do the latter. That's not independent in any sense. - Erick G. Hagstrom
(2) I will have to agree that the last sentence just does not follow (in fact, contradicts) with the answer itself. The whole answer proves that coroutines are, by definition, NOT concurrent - they are, in fact, mutually exclusive (no two of them can be executing "concurrently)". - Gerasimos R
@ErickG.Hagstrom: Yeah, you are right. I have updated the answer, thx! - Nan Xiao
(1) @GerasimosR: Yeah, you are right. I have updated the answer, thx! - Nan Xiao
(1) @NanXiao since you site Rob Pike: Rob specifically meant that quote to mean that coroutines are concurrency, because coroutines allow you to handle several things concurrently. Coroutines allow for "cooperative multitasking". On the next slide Pike contrasts this with parallelism, which is another form of concurrency, but has different implications. - Chris Clark
(9) @ChrisClark I agree with you. Coroutines are concurrency. Here is some quote from wikipedia: Coroutines are very similar to threads. However, coroutines are cooperatively multitasked, whereas threads are typically preemptively multitasked. This means that they provide concurrency but not parallelism. - smwikipedia
(3) And: Cooperative multitasking, also known as non-preemptive multitasking, is a style of computer multitasking in which the operating system never initiates a context switch from a running process to another process. Instead, processes voluntarily yield control periodically or when idle or logically blocked in order to enable multiple applications to be run concurrently. - smwikipedia
If the coroutines are not concurrency, does that mean they are effectively the same thread, and thus you cannot have a race condition between the coroutines? - Qwert Yuiop
3
[+20] [2020-06-24 18:48:16] Izana

I find an explanation from this link [1] is pretty straight forward. None of those answers try to explain concurrency vs parallelism except the last bullet point in this answer [2].

  1. what is concurrent (program)?

cited from "programming Erlang", by Joe Armstrong, the legendary:

a concurrent program can run potentially faster on a parallel computer.

  • a concurrent program is a program written in a concurrent programming language. We write concurrent programs for reasons of performance, scalability, or fault tolerance.

  • a concurrent programming language is a language that has explicit language constructs for writing concurrent programs. These constructs are an integral part of programming language and behave the same way on all operating systems.

  • a parallel computer is a computer that has several processing units (CPUs or cores) that can run at the same time.

So concurrency is not the same as parallelism. You can still write concurrent programs on a single-core computer. The time-sharing scheduler will make you feel your program is running concurrently.

The concurrent program has the potential to run in parallel in a parallel computer but not guaranteed. OS may only give you one core to run your program.

Therefore, concurrency is a software model from a concurrent program that doesn't mean your program can run in parallel physically.

  1. coroutine and concurrency

The word “coroutine” is composed of two words: “co” (cooperative) and “routines” (functions).

a. does it achieve concurrency or parallelism?

To be simple, let's discuss it on a single-core computer.

Concurrency is achieved by time-shares from OS. A thread executes its code in its assigned time frames on the CPU core. It can be preempted by OS. It may also yield control to OS.

A coroutine, on the other hand, yields control to another coroutine within the thread, not to OS. So all coroutines within a thread still exploit the time frame for that thread without yielding the CPU core to other threads managed by OS.

Therefore, you can think of coroutine achieves time-shares by the user not by OS (or quasi-parallelism). Coroutines run on the same core assigned to the thread that runs those coroutines.

Does Coroutine achieve parallelism? If it's CPU-bound code, no. Like time-shares, it makes you feel they run in parallel but their executions are interleaved not overlapped. If it's IO-bound, yes, it achieves parallel by hardware (IO devices) not by your code.

b. the difference with function call?

enter image description here

As the pic shows, it doesn't need to call return to switch control. It can yield without return. A coroutine saves and shares state on the current function frame (stack). So it's much more lightweight than function since you don't have to save registers and local variables to stack and rewind call stack when call ret.

[1] https://www.educative.io/edpresso/what-is-a-coroutine
[2] https://stackoverflow.com/a/62162266/5335565

4
[+16] [2016-06-21 16:35:25] Twinkle

Coroutine is similar to subroutine/threads. The difference is once a caller invoked a subroutine/threads, it will never return back to the caller function. But a coroutine can return back to the caller after executing a few piece of code allowing the caller to execute some of its own code and get back to the coroutine point where it stopped execution and continue from there. ie. A coroutine has more than one entry and exit points


(1) It is not so similar to threads - which run independently and simultaneously (separate cores in parallel). In addition the subroutine comparison fails in the sense that there are multiple independent paths of execution and they are not returning results to each other. - WestCoastProjects
5
[+14] [2017-10-07 13:38:44] Dhaval Jivani
  • Coroutines are great features available in Kotlin Language
  • Coroutines are a new way of writing asynchronous, non-blocking code (and much more)
  • Coroutine are light-weight threads. A light weight thread means it doesn’t map on native thread, so it doesn’t require context switching on processor, so they are faster.
  • it doesn’t map on native thread
  • Coroutines and the threads both are multitasking. But the difference is that threads are managed by the OS and coroutines by the users.

Basically, there are two types of Coroutines:

  1. Stackless
  2. Stackful

Kotlin implements stackless coroutines — it’s mean that the coroutines don’t have own stack, so they don’t map on native thread.

These are the functions to start the coroutine:

launch{}

async{}

You can learn more from here :

https://www.kotlindevelopment.com/deep-dive-coroutines/

https://blog.mindorks.com/what-are-coroutines-in-kotlin-bf4fecd476e9


(1) Good answer! Useful for Kotlin and Android developers. - Malwinder Singh
"Coroutines are great features available in Kotlin Language" what? No, it is Kotlin Coroutines. You have no freaking idea what you are talking about. I have sen al the lines in different articles, you just copy pasted all of these. If not please explain this "Coroutine are light-weight threads" in simpler terms - Farid
6
[+11] [2021-12-03 01:16:30] Heapify

If you are still confused, here is a very simple way of understanding a co-routine. First off, what is a routine? In a lay man's term, a routine is something that we do again and again (for example, your morning routine). Similarly. in programming languages, a routine is a piece of code that we use again and again, e.g., a function. Now, if you look at the general characteristic of a function or routine (note: I am cautiously using these two terms interchangeably), it takes some inputs and hogs the CPU threads for as long as the function needs to output the result. Meaning, functions or routines are blocking calls in you code. However, a co-routine is a special kind of routine that can co-exist (the "co" part of the word co-routine comes from this) with other routines at the same time and we can make this happen in programming languages with the help of asynchronous programming. In Asynchronous programming, when one co-routine is waiting for something to happen (e.g., disk io), the other co-routine will start working and when this co-routine is in a waiting state the other co-routine will be active ultimately reducing the waiting time of our code.

If you understand the above, let's see how you can create a co-routine function in Python. You can define a co-routine function as following -

async def my_coroutine_function():
    return 123

And you can the call the above co-routine by adding await in front of the co-routine-

my_result = await my_coroutine_function()

To conclude,

When you're watching a TV show and as soon as the Ad comes, you take your phone and text a friend - what you have just done is Asynchronous Programming. While your TV show (a co-routine) was on a waiting state, you went ahead and made your other co-routine (texting your friend) active.


7
[+8] [2021-09-07 09:56:32] user1473249581

Coroutine as an implementation of concurrency and alternative to multithreading.

A coroutine is a single-threaded solution to achieve concurrency.

         A-Start ------------------------------------------ A-End   
           | B-Start -----------------------------------------|--- B-End   
           |    |      C-Start ------------------- C-End      |      |   
           |    |       |                           |         |      |
           V    V       V                           V         V      V      
1 thread->|<-A-|<--B---|<-C-|-A-|-C-|--A--|-B-|--C-->|---A---->|--B-->| 

In comparison to a multithreading solution:

thread A->|<--A|          |--A-->|
thread B------>|<--B|            |--B-->|
thread C ---------->|<---C|             |C--->|

  • Coroutine is an implementation of asynchronous programming, and asynchronous programming is used to implement concurrency.
  • Many languages implemented asynchronous programming with coroutine. The other answers suggest Python, Kotlin, Lua, C++ have done so.
  • Most useful/typically used in scenarios involving I/O bound problems, like rendering UI while fetching data, or downloading from several data sources.

(2) First depiction is totally misleading it conveys a feeling that multiple routines are run simultaneously which is totally not what coroutines are doing - Farid
8
[+4] [2017-04-12 04:01:34] joseph

On a different note, in python gevent library is a coroutine based networking library which gives you threadlike features like async network requests, without the overhead of creating and destroying threads. The coroutine library used is greenlet.


9
[+2] [2019-05-31 08:58:29] Shihe Zhang

From Python Coroutine [1]:

Execution of Python coroutines can be suspended and resumed at many points (see coroutine). Inside the body of a coroutine function, await and async identifiers become reserved keywords; await expressions, async for and async with can only be used in coroutine function bodies.

From Coroutines (C++20) [2]

A coroutine is a function that can suspend execution to be resumed later. Coroutines are stackless: they suspend execution by returning to the caller. This allows for sequential code that executes asynchronously (e.g. to handle non-blocking I/O without explicit callbacks), and also supports algorithms on lazy-computed infinite sequences and other uses.

Compare with other's answer:

In my opinion, the resumed later part is a core difference, just like @Twinkle's.
Although many fields of the document are still work in progress, however, this part is similar to most answer, except @Nan Xiao 's

Coroutines, on the other hand, are collaborative: at any given time, a program with coroutines is running only one of its coroutines, and this running coroutine suspends its execution only when it explicitly requests to be suspended.

Since it's quoted from Program in Lua, maybe it's language related(not familiar with Lua currently), not all document mentioned the only one part.

The relation with concurrent:
There is an "Execution" part of the Coroutines (C++20) [3].Too long to quote here.
Besides the detail, there are several states.

When a coroutine begins execution  
When a coroutine reaches a suspension point  
When a coroutine reaches the co_return statement  
If the coroutine ends with an uncaught exception  
When the coroutine state is destroyed either because it terminated via co_return or uncaught exception, or because it was destroyed via its handle 

as the comment from @Adam Arold under @user217714's answer. It's concurrency.
But it's different from multithreading. from std::thread [4]

Threads allow multiple functions to execute concurrently. Threads begin execution immediately upon construction of the associated thread object (pending any OS scheduling delays), starting at the top-level function provided as a constructor argument. The return value of the top-level function is ignored and if it terminates by throwing an exception, std::terminate is called. The top-level function may communicate its return value or an exception to the caller via std::promise or by modifying shared variables (which may require synchronization, see std::mutex and std::atomic)

Since it's concurrency, it works like multithreading especially when waiting is unavoidable(from the OS perspective), that's also why it's confusing.

[1] https://docs.python.org/3/reference/compound_stmts.html#coroutine-function-definition
[2] https://en.cppreference.com/w/cpp/language/coroutines
[3] https://en.cppreference.com/w/cpp/language/coroutines
[4] https://en.cppreference.com/w/cpp/thread/thread

10
[+2] [2023-07-04 19:40:02] nightlytrails

There is a long street with banks, offices, shops, restaurants, schools along the way. You and your neighbors and friends and family's and perfect strangers, all of you living at that street have a job.

Now you start from home and take a Taxi. Midway, you have to stop at the bank to draw some cash. You hop off the taxi, because you don’t want to keep it waiting. Taxi is now free to give a ride to some one else with a job.

Once you are finished with your work in bank, you come out, wave at another Taxi that was waiting nearby and move along.

You all are Coroutines. Taxis are Threads.


11
[+1] [2020-03-24 20:01:57] WestCoastProjects

I will expand on @user21714 's answer. Coroutines are independent paths of execution that can not run simultaneously. They depend upon a controller - for example a python controller library - to handle switching between these paths. But for this to work the coroutines themselves need to invoke yield or similar structures that allow their execution to be paused.

Threads instead are running on independent compute resources and in parallel with each other. Since they are on different resources there is no need for invoking yield to allow the other paths of execution to proceed.

You can see this effect by starting a multihreaded program - e.g. a jvm application - in which all eight of your core i7 hyperthread cores are utilized: you might see 797% utilization in Activity Monitor or Top. Instead when running a typical python program - even one with coroutines or python threading - the utilization will max out at 100%. I.e. one machine hyperthread.


12
[+1] [2023-06-13 10:37:56] Lionel G

From Wikipedia [1]:

Coroutines are very similar to threads. However, coroutines are cooperatively multitasked, whereas threads are typically preemptively multitasked. Coroutines provide concurrency, because they allow tasks to be performed out of order or in a changeable order, without changing the overall outcome, but they do not provide parallelism, because they do not execute multiple tasks simultaneously. The advantages of coroutines over threads are that they may be used in a hard-realtime context (switching between coroutines need not involve any system calls or any blocking calls whatsoever), there is no need for synchronization primitives such as mutexes, semaphores, etc. in order to guard critical sections, and there is no need for support from the operating system.

It is possible to implement coroutines using preemptively-scheduled threads, in a way that will be transparent to the calling code, but some of the advantages (particularly the suitability for hard-realtime operation and relative cheapness of switching between them) will be lost.

[1] https://en.wikipedia.org/w/index.php?title=Coroutine&oldid=1222161955#Threads

13
[0] [2020-12-06 14:48:11] yoAlex5

Kotlin Coroutine

[Synchronous vs Asynchronous] [1]

[Concurrency vs Parallelism] [2]

Usually we heart something like - coroutines are light weight threads, they allow us to write asynchronous, non-blocking code in a synchronous manner

As for Kotlin Coroutines:

Coroutine is a synthetic sugar/additional layer which allows you to run a task in a non-blocking way and without callbacks. Coroutine consists of some components:

  • Continuation
  • Job - Manage courutine and save it's state
  • CoroutineScope (contains Job and Xontext) - handles group(hierarchy) of jobs and manage them(start and cancel)
  • Dispatcher - for working with thread pools - Main, IO, Default...
  • Context - data structure like Map to save some date like Job, Dispatcher and custom data

enter image description here

Lets review some example

class MyClass {
    val network = Network()
    val fileSystem = FileSystem()
    
    suspend fun downloadFile(): File {
        //suspendCoroutine is key point
        return suspendCoroutine { continuation -> 
            network.download(callback: Network.Callback {
                override fun onSuccess(file: File) {
                    continuation.resume(file)
                }
            })
        }
    }

    suspend fun saveFile(file: File) {
        //suspendCoroutine is key point
        return suspendCoroutine { continuation -> 
            fileSystem.save(callback: FileSystem.Callback {
                override fun onSuccess() {
                    continuation.resume()
                }
            })
        }
    }

    GlobalScope.launch {
        val downloadResult = downloadFile() //1. suspend function
        show(downloadResult)                //2. UI 
        saveFile(downloadResult)            //3. suspend function
    }

Continuation

It creates Continuation class which is state machine with invokeSuspend() function inside. invokeSuspend() is called(like callback) at the end of any suspend function

class Continuation {
    int label;

    //block of local variabels
    File file;
 
    void invokeSuspend(Object result) {
        switch (label) {
            case 0: {
                label = 1;
                downloadFile(this);    //1. suspend function
                return;
            }
            case 1: {
                file = (File) result;  //work with result
                show(file);            //2. UI
                saveFile(file, this);  //3.suspend function
                return;
            }
        }
    }
}

class MyClass {
    fun downloadFile(continuation: Continuation): File {
        //logic
        continuation.invokeSuspend(file)
    }

    fun saveFile(file: File, continuation: Continuation) {
        //logic
        continuation.invokeSuspend()
    }
}

suspended

  • suspended is just a marker for function where will be added new continuation argument(continuation: Continuation)
  • divides state machine, which means that it can pause the machine
  • suspended function should call Continuation inside Continuation.resume() -> Continuation.invokeSuspend()
  • suspended function can be called only from courutine

The main point that behavior of coroutine completely depends on library realisation

[1] https://stackoverflow.com/a/49386140/4770877
[2] https://stackoverflow.com/a/63744581/4770877

This explains nothing. As simple as that - Farid
14