Synchronous, asynchronous
In programming
sync/async execution
Asynchronous execution is, first and foremost, a description of how program coordination/flow is managed:
In contrast with synchronous execution, where the initiator waits for the thing they started to return control before it can move on...
...asynchronous execution means you can move on to another task before that finishes - and the result may arrive by some other method.
And nothing else
Note that 'how flow is managed' and in itself says nothing about
- which part of the system decides what to do in the meantime, or next (scheduling decisions)
- the mechanism by which the scheduler shares time among multiple tasks
- whether it's cooperative or pre-emptive multitasking
- what waiting does, and (often relatedly) how to block
- how parts communicate / how task results get back to you (e.g. shared memory, message passing, notifications)
- what state a task keeps (and shares, if it does so at all)
- whether we can do parallel or just concurrent (involves hardware details)
Those are separate pieces of the same puzzle.
And while most of async isn't a complex topic, details vary between async systems.
If someone hands you something running async code, it had to bring its own execution and had to make choices for each of those.
So which parts are inherently async, and which are just choices? That part makes it hard to keep all the separations clean, and easy to conflate stuff, and hard to pick it up by osmosis, as it's easy to assume that whatever you saw first is what async is all about. This seems to be where most of the confusion comes from. (That and that most tutorials only introduce the specific system they're describing)
Are event loops async?
- Not really, but they just often happen to be a natural choice within various async setups. (And in some sync ones)
Is async about cooperative scheduling?
- No, pre-emptive async exists too (though it's a conscious choice).
Is async about lack of stacks?
- In general, no.
- In higher level abstractions often yes but for a specific reason.
Is sync=blocking and async=non-blocking?
- That's sort of the default, but
- there are ways to do blocking in async code, and
- there are ways to do non-blocking in otherwise-sync code.
Note that async execution happening far predates async programming in the smoother, higher-level programming languageswe have today.
Consider how DMA transfers, hardware interrupts, but also OS APIs such as signal handlers, callback-based OS APIs, completion ports, all fit the 'flow allows us to do other things'.
And you could look at anything that doesn't directly know about each other, and call it async with regard to each other - processes to each other and to the OS, threads to each other, etc.
...but we have more useful, descriptive terms for the specific within those systems.
You could see some families within async, e.g.
- system-level asynchrony - OS was always async with its processes,
- structured async programming - often a cooperative model within a single process
- groups a few ways of interchange, which tend to easily become means of coordination
- Threaded concurrency - less structure, coordination optional
- RTOS
- is a specific pre-emptive model, and deadline-oriented - and often a little more event-driven(verify).
- (were many other async styles are cooperative, and relatively throughput-oriented)
But note that this is drawing some arbitrary lines between more options.
Each of them makes it easier to focus on different aspects of the same issues. Say,
- process-system ends up focusing on robustness and handling events from outside,
- structured async focuses on 'how do make things cleanly coordinated'
- threading focuses on 'how do we safely share'
- RTOS focuses on 'how do we guarantee things happen in deadlines'
(note: you might be looking specifically for python async)
sync IO / async IO
synchronous IO is also known as blocking IO, usually indicates when code does an IO call where that IO code can/will make you wait until it's done - the execution of the calling program will stop until the function says that it's done.
- (like any function call, but just pointing out that the function is waiting on IO to complete rather than on CPU doing calculation)
- This is the simplest way of safely doing IO, both for the underlying library and OS, and for a program
asynchronous IO describes any situation where IO doesn't block execution.
This is useful when your code can do other work (other CPUwork, other IO)
- usually requests you fire off and check back on later
- often about the practical question "could we have gotten other things done in a program, instead of completely halting?"
Usually indicates some amount of concurrency -- which is often abstracted out for you at least a little.
Notes:
- there is often a useful distinction between whether a program does sync or async (sys)calls towards the kernel/OS
- ...because a multitasking kernel/OS's IO subsystem is almost necessarily asynchronous
- ...and intentionally a design requirement for its parts
- ...and ideally its task scheduler is aware of IO, because that makes it easy to not waste time scheduling tasks that are currently blocked on IO anyway
- in some ways, we're just moving the blocking to another place (specific parts of the the OS's IO subsystem), yet this has made a lot of sense since the time multitasking became a thing: the OS is nicely parallelized, and is also the one scheduling you, also meaning it can be clever in ways you no longer have to be.
- relatedly, if a program does a blocking (sync) call towards the OS, the OS may have set up a smallish buffer to accept some data immediately (to itself get to soon and separately), which means writes do not always lead to any actual blocking of the calling program (and may do so only rarely, particularly for smaller or rarer writes)
- async IO is also associated with a coding style that does concurrency via cooperative multitasking (single thread and/or event loop), because you practically won't get very far with such async execution without async IO.
- if you consider IO and CPU different subsystems, then sync is using them sequentially, and async is using them concurrently.
- so async can be more efficient (under certain assumptions)
See also:
sync/async servers
sometimes: delayed loading
'async' sometimes just means some variant of "when there's nothing else on my TODO list", or lazy evaluation
For example, putting async on a JS script tag means "whenever you get to it, I've go no dependencies to worry about"