I suggest you review Concurrency — The Swift Programming Language (Swift 5.7), it should answer your questions. In short, awaits are suspension points which allow code to continue executing elsewhere. Combined with your use of Task, which puts its content onto a separate line of execution in the same context, and there's nothing to block at all.
what is the key difference between these two snippets?
To expand on patrickgoley’s reply, async/await and Dispatch are very different things:
When you wait on a semaphore, that translates to a call to the Dispatch C API, dispatch_semaphore_wait, that blocks the current thread until unblocked by the semaphore send.
Async functions are run by a small pool of cooperative threads. When you await in an async function, you don’t block that thread. Rather, the Swift compiler rewrites your code to save its state in memory associated with the task and returns control to the runtime. That thread is then free to continue doing other work. When the async function that you’re waiting on completes, the runtime finds a thread to continue execution of your function, restores its saved state from the task, and away you go.