主线程上的异步任务是否与同步任务相同?

时间:2020-03-30 08:33:35

标签: ios swift grand-central-dispatch

我知道两种之间的区别。

对于异步任务,下一个任务将在当前任务开始后运行,这意味着如果有可用线程,则任务将分派到多个线程。 对于同步任务,下一个任务将在当前任务完成后运行。

主线程只有一个线程,如何运行异步任务?

这让我感到困惑。
提前致谢。

2 个答案:

答案 0 :(得分:5)

您对异步和同步的定义不太正确。

在Grand Central Dispatch中,您考虑的是队列,而不是线程。队列可以是串行调度队列,也可以是并发调度队列。

串行分派队列可以一次运行一个任务,然后一个任务接一个地分派(串行)。

并发调度队列可以在多个线程上同时运行多个任务。

任务在线程上执行,Grand Central Dispatch负责为您分配任务给线程。

主队列是一个特殊的串行调度队列,仅将任务分配给主线程。其他队列可以将任务分配给任何可用线程,包括主线程。

现在,对于同步与异步分派,区别在于分派是阻塞当前线程直到分派的任务完成(同步),还是将任务排队而不阻塞当前线程(异步)。

当您异步调度到主队列时,您将提供一个工作单元,Grand Central Dispatch将在将来的某个时间分配给主线程,但是您的代码将继续执行,而无需等待该调度项完成。

您可以在异步队列上愉快地运行时将异步任务分配给主队列,因为当主队列准备好执行任务时,被分配的任务将在稍后执行。

您不能做的是将同步调度到主队列 从主队列(或更一般地说,从同一队列同步调度到任何串行调度队列),因为您将创建死锁。

分派同步地阻塞当前线程/队列,直到分派的项目完成为止。在串行调度队列上,由于调度队列被阻塞,因此无法执行调度项目。

答案 1 :(得分:2)

对于异步任务,下一个任务将在当前任务开始后运行,这意味着如果有可用线程,则任务将分派到多个线程。

不完全是。异步分配仅意味着当前线程将等待分配的代码完成。与目标队列是串行队列还是并发队列完全无关。

对于同步任务,下一个任务将在当前任务完成后运行。

再次,不太完全。同步分派仅意味着当前线程 将等待分派的代码完成执行。

被调度的代码是否与先前调度到该队列的其他项目同时运行是由队列类型(即串行或并发)决定的,而不是我们是同步调度还是异步调度。

主线程只有一个线程,如何运行异步任务?

现在可能已经很明显了,“异步”与“同步”不是正在分派的任务的特征,而是仅指示您是否应该等待从中分派的线程。

因此,请考虑一些将代码异步分派回主线程的代码:

let task = URLSession.dataTask(with: request) { data, _, _ in
    let results = ...                 // on `URLSession` background serial queue, only populate local variables
    DispatchQueue.main.async {
        self.objects = results        // dispatch model updates back to main queue
        self.tableView.reloadData()   // also update UI from main queue
    }
}
task.resume()

在上面的示例中,我们将模型和UI更新分派到主队列,因为我们位于URLSession后台队列(也恰好是串行队列)中。而且我们异步进行调度,因为URLSession的串行队列没有理由等待调度的代码完成。我们可以同步调度它,但是为什么我们还要打扰URLSession队列,即使只是多花几毫秒。