Ios GCD中的并发队列与串行队列
我很难完全理解GCD中的并发队列和串行队列。我有一些问题,希望有人能及时清楚地回答我Ios GCD中的并发队列与串行队列,ios,multithreading,concurrency,grand-central-dispatch,Ios,Multithreading,Concurrency,Grand Central Dispatch,我很难完全理解GCD中的并发队列和串行队列。我有一些问题,希望有人能及时清楚地回答我 我读到串行队列是为了一个接一个地执行任务而创建和使用的。但是,如果: 我创建了一个串行队列 我使用dispatch\u async(在我刚刚创建的串行队列上)三次来调度三个块A、B、C 将执行三个块: 顺序为A、B、C,因为队列是串行的 或 并发(同时在parralel线程上),因为我使用了异步调度 我读到我可以在并发队列上使用dispatch\u sync,以便一个接一个地执行块。在这种情况下,为什么
- 我创建了一个串行队列
- 我使用
(在我刚刚创建的串行队列上)三次来调度三个块A、B、Cdispatch\u async
- 顺序为A、B、C,因为队列是串行的 或
- 并发(同时在parralel线程上),因为我使用了异步调度
dispatch\u sync
,以便一个接一个地执行块。在这种情况下,为什么还要存在串行队列,因为我可以始终使用并发队列,在该队列中,我可以同步调度任意数量的块
谢谢你的解释一个简单的例子:您有一个需要一分钟才能执行的块。您可以从主线程将其添加到队列中。让我们看看这四个案例
- 异步并发:代码在后台线程上运行。控件立即返回到主线程(和UI)。块不能假定它是该队列上运行的唯一块
- 异步-串行:代码在后台线程上运行。控件立即返回到主线程。该块可以假定它是该队列上运行的唯一块
- sync-concurrent:代码在后台线程上运行,但主线程等待它完成,从而阻止对UI的任何更新。该块不能假定它是该队列上运行的唯一块(我可以在几秒钟之前使用async添加另一个块)
- sync-serial:代码在后台线程上运行,但主线程等待它完成,从而阻止对UI的任何更新。该块可以假定它是该队列上运行的唯一块
显然,对于长时间运行的进程,您不会使用后两种方法中的任何一种。通常,当您试图从另一个线程上运行的某个内容更新UI(始终在主线程上)时,您会看到它。以下是我做的几个实验,以使我了解这些
串行
,并发
队列和大型中央调度
func doLongAsyncTaskInSerialQueue() {
let serialQueue = DispatchQueue(label: "com.queue.Serial")
for i in 1...5 {
serialQueue.async {
if Thread.isMainThread{
print("task running in main thread")
}else{
print("task running in background thread")
}
let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
let _ = try! Data(contentsOf: imgURL)
print("\(i) completed downloading")
}
}
}
在GCD中使用异步时,任务将在不同的线程(主线程除外)中运行。异步意味着执行下一行不等待块执行,这将导致非阻塞主线程和主队列。
由于它是串行队列,所以所有任务都按照它们添加到串行队列的顺序执行。串行执行的任务总是由与队列关联的单个线程一次执行一个
在GCD中使用同步时,任务可能会在主线程中运行。Sync在给定队列上运行一个块并等待它完成,这将导致阻塞主线程或主队列。由于主队列需要等待,直到分派的块完成,主线程将可用于处理来自主队列以外的队列的块。因此,在后台队列上执行的代码可能实际上正在主线程上执行
由于它是串行队列,所以所有操作都是按照添加顺序(FIFO)执行的
在GCD中使用异步时,任务将在后台线程中运行。异步意味着执行下一行不等待块执行,这将导致非阻塞主线程。
请记住,在并发队列中,任务是按照添加到队列的顺序处理的,但不同的线程连接到队列
队列记住,他们不应该按顺序完成任务
它们被添加到队列中。每次任务的顺序都不同
线程是自动创建的,任务是并行执行的。超过
如果达到(maxConcurrentOperationCount),则某些任务将正常运行
作为串行,直到线程空闲
在GCD中使用同步时,任务可能会在主线程中运行。Sync在给定队列上运行一个块并等待它完成,这将导致阻塞主线程或主队列。由于主队列需要等待,直到分派的块完成,主线程将可用于处理来自主队列以外的队列的块。因此,在后台队列上执行的代码可能实际上正在主线程上执行。
由于其并发队列,任务可能不会按照添加到队列中的顺序完成。但对于同步操作,它确实可以,尽管它们可能由不同的线程处理。因此,它的行为就像这是串行队列一样
以下是这些实验的总结
请记住,使用GCD时,您只是将任务添加到队列并从该队列执行任务。队列根据操作是同步还是异步,在主线程或后台线程中调度任务。队列类型包括串行、并发和主调度队列。默认情况下,您执行的所有任务都是从主调度队列完成的。应用程序已经有四个预定义的全局并发队列可供使用,还有一个主队列(DispatchQueue.Main)。您也可以手动创建自己的队列并从该队列执行任务
UI相关的任务应始终通过将任务分派到主队列从主线程执行。简写实用程序为DispatchQueue.main.sync/async
,而与网络相关的/繁重的操作应始终异步执行,无论您使用的是主线程还是后台线程
编辑:
但是,在某些情况下,您需要在后台线程中同步执行网络调用操作,而不冻结UI(例如,刷新OAuth令牌并等待成功与否)。您需要将该方法包装在异步操作中
func doLongSyncTaskInSerialQueue() {
let serialQueue = DispatchQueue(label: "com.queue.Serial")
for i in 1...5 {
serialQueue.sync {
if Thread.isMainThread{
print("task running in main thread")
}else{
print("task running in background thread")
}
let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
let _ = try! Data(contentsOf: imgURL)
print("\(i) completed downloading")
}
}
}
func doLongASyncTaskInConcurrentQueue() {
let concurrentQueue = DispatchQueue(label: "com.queue.Concurrent", attributes: .concurrent)
for i in 1...5 {
concurrentQueue.async {
if Thread.isMainThread{
print("task running in main thread")
}else{
print("task running in background thread")
}
let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
let _ = try! Data(contentsOf: imgURL)
print("\(i) completed downloading")
}
print("\(i) executing")
}
}
func doLongSyncTaskInConcurrentQueue() {
let concurrentQueue = DispatchQueue(label: "com.queue.Concurrent", attributes: .concurrent)
for i in 1...5 {
concurrentQueue.sync {
if Thread.isMainThread{
print("task running in main thread")
}else{
print("task running in background thread")
}
let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
let _ = try! Data(contentsOf: imgURL)
print("\(i) completed downloading")
}
print("\(i) executed")
}
}
func doMultipleSyncTaskWithinAsynchronousOperation() {
let concurrentQueue = DispatchQueue(label: "com.queue.Concurrent", attributes: .concurrent)
concurrentQueue.async {
let concurrentQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default)
for i in 1...5 {
concurrentQueue.sync {
let imgURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
let _ = try! Data(contentsOf: imgURL)
print("\(i) completed downloading")
}
print("\(i) executed")
}
}
}
PlaygroundPage.current.needsIndefiniteExecution = true
let cq = DispatchQueue(label: "concurrent.queue", attributes: .concurrent)
let cq2 = DispatchQueue(label: "concurent.queue2", attributes: .concurrent)
let sq = DispatchQueue(label: "serial.queue")
func codeFragment() {
print("code Fragment begin")
print("Task Thread:\(Thread.current.description)")
let imgURL = URL(string: "http://stackoverflow.com/questions/24058336/how-do-i-run-asynchronous-callbacks-in-playground")!
let _ = try! Data(contentsOf: imgURL)
print("code Fragment completed")
}
func serialQueueSync() { sq.sync { codeFragment() } }
func serialQueueAsync() { sq.async { codeFragment() } }
func concurrentQueueSync() { cq2.sync { codeFragment() } }
func concurrentQueueAsync() { cq2.async { codeFragment() } }
func tasksExecution() {
(1...5).forEach { (_) in
/// Using an concurrent queue to simulate concurent task executions.
cq.async {
print("Caller Thread:\(Thread.current.description)")
/// Serial Queue Async, tasks run serially, because only one thread that can be used by serial queue, the underlying thread of serial queue.
//serialQueueAsync()
/// Serial Queue Sync, tasks run serially, because only one thread that can be used by serial queue,one by one of the callers' threads.
//serialQueueSync()
/// Concurrent Queue Async, tasks run concurrently, because tasks can run on different underlying threads
//concurrentQueueAsync()
/// Concurrent Queue Sync, tasks run concurrently, because tasks can run on different callers' thread
//concurrentQueueSync()
}
}
}
tasksExecution()
serialQueue.async {
// this is one task
// it can be any number of lines with any number of methods
}
serialQueue.async {
// this is another task added to the same queue
// this queue now has two tasks
}
let serialQueue = DispatchQueue(label: "serial")
let concurrentQueue = DispatchQueue(label: "concurrent", attributes: [.concurrent])
let concurrentQueue = DispatchQueue.global(qos: .default)
DispatchQueue.global(qos: .default).sync {
// task goes in here
}
DispatchQueue.global(qos: .default).async {
// task goes in here
}
whichQueueShouldIUse.syncOrAsync {
for i in 1...10 {
print(i)
}
for i in 1...10 {
print(i + 100)
}
for i in 1...10 {
print(i + 1000)
}
}
let serialQueue = DispatchQueue(label: "serial")
let concurrentQueue = DispatchQueue.global(qos: .default)
concurrentQueue.async {
for i in 1...5 {
print(i)
}
}
concurrentQueue.async {
for i in 1...5 {
print(i + 100)
}
}
1
101
2
102
103
3
104
4
105
5
serialQueue.async {
for i in 1...5 {
print(i)
}
}
concurrentQueue.async {
for i in 1...5 {
print(i + 100)
}
}
101
1
2
102
3
103
4
104
5
105
serialQueue.async {
for i in 1...5 {
print(i)
}
}
serialQueue.async {
for i in 1...5 {
print(i + 100)
}
}
1
2
3
4
5
101
102
103
104
105
serialQueue.async {
for i in 1...5 {
print(i)
}
}
serialQueue2.async {
for i in 1...5 {
print(i + 100)
}
}
1
101
2
102
3
103
4
104
5
105
serialQueue.async {
for i in 1...5 {
print(i)
}
}
serialQueue.async {
for i in 1...5 {
print(i + 100)
}
}
concurrentQueue.async {
for i in 1...5 {
print(i + 1000)
}
}
1
2
3
4
5
101
102
103
104
105
1001
1002
1003
1004
1005
1
1001
1002
1003
2
1004
1005
3
4
5
101
102
103
104
105
concurrentQueue.sync {
for i in 1...5 {
print(i)
}
}
concurrentQueue.async {
for i in 1...5 {
print(i + 100)
}
}
1
2
3
4
5
101
102
103
104
105
DispatchQueue.main.sync { ... }
DispatchQueue.main.sync { // stop the main queue and wait for the following to finish
print("hello world") // this will never execute on the main queue because we just stopped it
}
// deadlock
let serialQueue = DispatchQueue(label: "serialQueue", qos: .default, attributes: [], autoreleaseFrequency: .inherit, target: .global(qos: .default))
let serialQueue = DispatchQueue(label: "SampleSerialQueue")
//Block first
serialQueue.async {
for i in 1...10{
print("Serial - First operation",i)
}
}
//Block second
serialQueue.async {
for i in 1...10{
print("Serial - Second operation",i)
}
}
//Block Third
serialQueue.async {
for i in 1...10{
print("Serial - Third operation",i)
}
}