swiftgrand-central-dispatchswift-concurrency

What's difference btw DispatchQueue.global(qos: .background).async {} and Task(priority: .background) {} in Swift


I can see Swift support 2 kinds of background task

Using DispatchQueue

DispatchQueue.global(qos: .background).async {}

Using Task

Task(priority: .background) {} 

So I am confusing about what's the difference and which one should I use?


Solution

  • These are two completely different patterns (despite the superficially similar reference to a .background QoS/priority). These two approaches are used in entirely different situations. This is a gross over-simplification, but:

    So, the question is more fundamental than DispatchQueue.global.async {…} vs Task {…}. The real question is GCD vs Swift concurrency. (And we almost always avoid intermixing GCD with Swift concurrency, except where absolutely necessary, but that is beyond the scope of this question. We would generally pick either GCD or Swift concurrency, and use that particular tech stack consistently within the given project.)

    In contemporary codebases, we would adopt Swift concurrency (and thus favor Task {…}, or, where you can, stick with structured concurrency), but if you are saddled with some legacy GCD codebase, then you might use global dispatch queues for the slow/synchronous work.


    By the way, I would advise being a little more clear with the term “background task”. Specifically, I might encourage you to avoid conflating the term with a Swift concurrency TaskPriority of .background or a global dispatch queue with a QoSClass of .background).

    Traditionally, when we abstractly talk about a “background task” we mean “get it off the current thread”. But, the task “priority” and/or the dispatch queue “quality of service” is more of a question of the relative priority of this work with respect to other work also submitted.


    Finally, it is worth stating that Task {…} does not get work off the current context. In fact, quite the opposite is true: Task {…} will run the work on behalf of the current actor. Using Task.detached {…} is probably closer to the idea of a global dispatch queue, but even that is an imperfect analogy.

    For more information, see The Swift Programming Language: Concurrency: Unstructured Concurrency or WWDC 2021 videos Meet async/await and Swift concurrency: Behind the scenes.