An event loop essentially manages and distributes the execution of different tasks. It registers them and handles distributing the flow of control between them.
Coroutines:
Coroutines are special functions that work similarly Python generators that on await they release the flow of control back to the event loop. A coroutine needs to be scheduled to run using the event loop, to do this we create a Task, which is a type of Future.
Futures:
Futures are objects that represent the result of a task that may or may not have been executed. This result may be an exception.