官术网_书友最值得收藏!

Tasks and queues

Queues are objects that abstract series of operations to execute. The system creates many queues for you, but the most important one is probably the main queue. Queues come in two major flavors, as follows:

  • Serial: A serial queue guarantees that no two operations will be executed at the same time. This is a particularly interesting feature if you need to write thread-safe code.
  • Concurrent: A concurrent queue will let different operations run in parallel, which can also be a very interesting feature.

As we mentioned previously, a serial queue is a queue that guarantees that no two operations will be run in parallel. The main queue of our apps, which you can access through DispatchQueue.main, is a serial queue. This is helpful to know, as the UI of iOS and macOS apps is run on the main thread. The execution of tasks on the main thread will be in order.

Let's consider the following code:

DispatchQueue.main.async {
print("operation 1")
DispatchQueue.main.async {
print("operation 1.1")
}
}

DispatchQueue.main.async {
print("operation 2")
}
Take a minute to think about what order you expect the logs to be printed in.

The output is as follows:

operation 1
operation 2
operation 1.1

The operations are executed in the order that they were enqueued. This is why operation 2 runs before operation 1.1. This is guaranteed, because the main queue is a serial queue. In a concurrent queue, this would not be guaranteed, and operations could be run out of order. 

Let's spice things up and run this series multiple times, with different queues, considering the following function run, which takes a queue and a number of executions. This function will run as many times as it is asked, on the provided queue, using the same logic that we ran previously:

func run(queue: DispatchQueue, times: Int) {
(0..<times).forEach { i in
queue.async {
print("\(i) operation 1")
queue.async { print("\(i) operation 1.1") }
}
queue.async {
print("\(i) operation 2")
}
}
}

When calling with run(queue: .main, times: 3), the results are consistent with a serial queue:

0 operation 1
0 operation 2
1 operation 1
1 operation 2
2 operation 1
2 operation 2
0 operation 1.1
1 operation 1.1
2 operation 1.1

All operations are executed in the order in which they have been enqueued. However, can you guess what will happen if we plug in a concurrent queue? See the following:

let queue = DispatchQueue(label: "com.run.concurrent",
attributes: .concurrent)
run(queue: queue, times: 3)
Take a minute to write on a piece of paper what you can suppose about the concurrent queue execution order.

The execution is actually unpredictable. Running the program multiple times will always yield a different output. Let's take a look at the following table:

 

As we can clearly see in the preceding table, every run has a slightly different execution order. We've repeated these simple tasks just a few times, and we didn't execute large computations or slow operations that would amplify this behavior.

Let's take a look at how we can use the Dispatch library to coordinate multiple operations with precision, and ensure the order of execution.

主站蜘蛛池模板: 平度市| 兴和县| 普宁市| 凯里市| 黄冈市| 延长县| 贵州省| 廉江市| 仪陇县| 常州市| 特克斯县| 阿拉尔市| 荆州市| 象山县| 宜良县| 泗阳县| 松潘县| 乌拉特前旗| 三河市| 余姚市| 淮阳县| 昭平县| 亚东县| 固阳县| 远安县| 金阳县| 噶尔县| 阿尔山市| 益阳市| 渭南市| 河北省| 鄂托克前旗| 乐清市| 柳河县| 久治县| 城步| 昌吉市| 镇坪县| 西畴县| 井研县| 仙居县|