Remix.run Logo
nine_k 2 days ago

Threads are more expensive and slow to create. Submitting a task to a thread pool and waiting for a result, or a bunch of results, to show up, is much more ergonomic. So `async` automatically submits a task, and `await` awaits until it completes. Ideally `await` just discovers that a task (promise) has completed at that point, while the main thread was doing other things.

Once you have this in place, you can notice that you can "submit the task to the same thread", and just switch between tasks at every `await` point; you get coroutines. This is how generators work: `yield` is the `await` point.

If all the task is doing is waiting for I/O, and your runtime is smart enough to yield to another coroutine while the I/O is underway, you can do something useful, or at least issue another I/O task, not waiting for the first one to complete. This allows typical server code that does a lot of different I/O requests to run faster.

Older things like `gevent` just automatically added yield / await points at certain I/O calls, with an event loop running implicitly.