You can see the async keyword on a function definition as a hint to the caller, that the action will be IO bound rather than CPU bound.
Caller can use this information to invoke 10000 IO bound tasks in parallel, whereas cpu bound tasks are limited to number of cores and may want to be throttled. In your analogy, I can eat a donut while simultaneously listening to music, but I can not eat a donut while simultaneously eating fish soup.
Now where it get complicated is when a function does both io wait and heavy cpu processing. Now neither color of the function match.
Forcing this upon the caller to invoke such functions in special ways is the strange part. Taken to the absurd you ought to have special syntax for every resource constraint in the computer, memory bound, disk bound, wifi bound, and so on. It would be better if the runtime could figure this out by itself and parallelize accordingly.
The single threaded aspect of async functions does have certain other benefits, like not having to care as much about muxes when synchronizing state.