Contrast that to coroutines/fibers where tasks(i.e functions), which run in the same I/O thread(though not an absolute requirement). Cooperative multitasking is used, where a running function can yield control to other runnable functions by explicitly calling a yield like function -- that is, there is no scheduler that preemptively stops a function and runs another. You need to do that yourself.
There is some overlap between the benefits and properties of tasks that run on OS threads and fibers, but for the most part, they have different pros and cons. You can't really use in practice fibers to get the benefits you get from a GCD like framework (which utilizes multiple H/W cores to run functions/tasks concurrently), but also, you can't use GCD to improve throughput on a per-thread basis and deal with long-running and/or blocking lightweight tasks, or implement a fair-scheduling execution scheme).
Fully fledged coroutines let you save and resume execution in place. The main advantage is readability of conditional/looping control flow, which tends to quickly devolve into a mess in callback style code.