主线程上的异步任务与同步任务相同吗?
are asynchronous tasks on main thread same as synchronous tasks?
我知道这两种的区别
对于异步任务,下一个任务将在当前任务开始后运行,这意味着如果有可用线程,任务将被分派到多个线程。
对于同步任务,下一个任务将在当前任务完成后 运行。
主线程运行只有一个线程怎么可能异步任务?
这让我很困惑。
提前致谢。
您对异步和同步的定义不太正确。
在 Grand Central Dispatch 中,您考虑的是 队列,而不是 线程。队列是串行调度队列或并发调度队列。
串行调度队列一次可以运行一个任务,任务一个接一个地(串行)调度。
一个并发调度队列可以运行在多个线程上同时执行多个任务。
任务在线程上执行,Grand Central Dispatch 负责为您将任务分配给线程。
主队列是一个特殊的串行调度队列,只给主线程分配任务。其他队列可以将任务分配给任何可用的线程,包括主线程。
现在,对于同步调度和异步调度,区别在于调度是阻塞当前线程直到调度任务完成(同步),还是将任务排队而不阻塞当前线程(异步)。
当您异步分派到主队列时,您提供了一个工作单元,Grand Central Dispatch 将在未来某个时间分配给主线程,但您的代码会继续执行,而无需等待分派的项目完成。
当 运行在主队列上运行时,您可以非常愉快地将异步任务分派到主队列,因为分派的任务将稍后执行,当主队列准备好任务时。
你不能做的是同步分派到主队列从主队列(或者更一般地说,同步分派到来自同一队列的任何串行调度队列),因为您将创建死锁。
同步分派会阻塞当前 thread/queue,直到分派的项目完成。在串行调度队列上,调度项无法执行,因为调度队列被阻塞。
For async tasks, next task will run after the current one began, which means tasks will be dispatched to multiple threads if there are threads available.
不完全是。异步分派仅意味着当前线程将不会等待分派的代码完成。它与目标队列是串行还是并发完全无关。
For sync tasks, next task will run after the current one finished.
同样,不完全是。仅同步分派意味着当前线程将等待分派的代码完成执行。
分派代码是否与之前分派到该队列的其他项目并发运行取决于队列类型(即串行或并发),而不是我们是同步分派还是异步分派。
How could main thread run async tasks since it only has one thread?
现在很明显,“异步”与“同步”并不是被分派任务的特征,而是仅指示您分派的线程是否应该等待。
因此,考虑一些将代码异步分派回主线程的代码:
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
队列,即使只是多出几毫秒。
我知道这两种的区别
对于异步任务,下一个任务将在当前任务开始后运行,这意味着如果有可用线程,任务将被分派到多个线程。
对于同步任务,下一个任务将在当前任务完成后 运行。
主线程运行只有一个线程怎么可能异步任务?
这让我很困惑。
提前致谢。
您对异步和同步的定义不太正确。
在 Grand Central Dispatch 中,您考虑的是 队列,而不是 线程。队列是串行调度队列或并发调度队列。
串行调度队列一次可以运行一个任务,任务一个接一个地(串行)调度。
一个并发调度队列可以运行在多个线程上同时执行多个任务。
任务在线程上执行,Grand Central Dispatch 负责为您将任务分配给线程。
主队列是一个特殊的串行调度队列,只给主线程分配任务。其他队列可以将任务分配给任何可用的线程,包括主线程。
现在,对于同步调度和异步调度,区别在于调度是阻塞当前线程直到调度任务完成(同步),还是将任务排队而不阻塞当前线程(异步)。
当您异步分派到主队列时,您提供了一个工作单元,Grand Central Dispatch 将在未来某个时间分配给主线程,但您的代码会继续执行,而无需等待分派的项目完成。
当 运行在主队列上运行时,您可以非常愉快地将异步任务分派到主队列,因为分派的任务将稍后执行,当主队列准备好任务时。
你不能做的是同步分派到主队列从主队列(或者更一般地说,同步分派到来自同一队列的任何串行调度队列),因为您将创建死锁。
同步分派会阻塞当前 thread/queue,直到分派的项目完成。在串行调度队列上,调度项无法执行,因为调度队列被阻塞。
For async tasks, next task will run after the current one began, which means tasks will be dispatched to multiple threads if there are threads available.
不完全是。异步分派仅意味着当前线程将不会等待分派的代码完成。它与目标队列是串行还是并发完全无关。
For sync tasks, next task will run after the current one finished.
同样,不完全是。仅同步分派意味着当前线程将等待分派的代码完成执行。
分派代码是否与之前分派到该队列的其他项目并发运行取决于队列类型(即串行或并发),而不是我们是同步分派还是异步分派。
How could main thread run async tasks since it only has one thread?
现在很明显,“异步”与“同步”并不是被分派任务的特征,而是仅指示您分派的线程是否应该等待。
因此,考虑一些将代码异步分派回主线程的代码:
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
队列,即使只是多出几毫秒。