Skip to content

Commit f068545

Browse files
author
Tom
committed
fix: CR 意见修改
1 parent b50ddf5 commit f068545

File tree

1 file changed

+12
-11
lines changed

1 file changed

+12
-11
lines changed

swift-6-beta.docc/LanguageGuide/Concurrency.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ Swift 原生支持结构化的异步和并行代码。
66

77
*异步代码*是能够被暂时挂起并在稍后继续执行的代码,不过在同一时刻中只有一段程序代码执行。通过挂起和恢复代码,你的程序就可以在执行耗时很长的任务时抽空执行一些快速的操作,比如在下载文件、解析文件的过程中更新 UI。*并行代码*则意味着多段代码可以在同一时刻执行;例如,一台拥有四核处理器的电脑可以同时运行四段代码(每个核心执行一项任务)。一款运用并行和异步代码编写的程序可以同时运行多个任务,且可以在等待外部系统处理时,暂时挂起一些任务。
88

9-
并发和异步代码在增加调度灵活性的同时,也会增加复杂度。Swift 能够在你在编写异步代码时,提供一些编译时检查——例如,你可以使用 actor 来安全地访问可变状态。然而,为一段运行缓慢或是有错误的代码添加并发能力,并不一定就能使它变得更快速或者更正确地运行。事实上,简单地为代码增加并发能力甚至可能导致代码问题更难排查。不过,对于的确有必要并发执行的代码来说,Swift 语言级别的并发支持能帮助你在编译时就捕捉到错误。
9+
并发和异步代码在增加调度灵活性的同时也会增加复杂度。Swift 能够在你在编写异步代码时,提供一些编译时检查——例如,你可以使用 actor 来安全地访问可变状态。然而,为一段运行缓慢或是有错误的代码添加并发能力,并不一定就能使它变得更快速或者更正确地运行。事实上,简单地为代码增加并发能力甚至可能导致代码问题更难排查。不过,对于的确有必要并发执行的代码来说,Swift 语言级别的并发支持能帮助你在编译时就捕捉到错误。
1010

1111
本章剩余的部分将使用*并发*一词指代异步和并行代码这一常见的组合。
1212

1313
> 如果你曾经编写过并发代码的话,那你可能习惯于使用线程。Swift 中的并发模型基于线程,但你不会直接与线程打交道。在 Swift 中,一个异步函数可以交出它在某个线程上的运行权 —— 这样,另一个异步函数在这个函数被阻塞时就能获得此在此线程上的运行权。但是,Swift 并不保证异步函数恢复运行时其将在哪条线程上运行。
1414
15-
你当然也可以不用 Swift 原生支持去写并发的代码,但这样代码的可读性会下降。比如,下面的这段代码会拉取一系列图片名称的列表,下载列表中的图片然后展示给用户
15+
你当然也可以不用 Swift 原生支持去写并发的代码,但这样代码的可读性会下降。比如,下面的这段代码会拉取一系列图片名称的列表,下载列表中的第一张图片然后展示给用户
1616

1717
```swift
1818
listPhotos(inGallery: "Summer Vacation") { photoNames in
@@ -52,7 +52,7 @@ listPhotos(inGallery: "Summer Vacation") { photoNames in
5252

5353
*异步函数**异步方法* 是一种能在运行中被挂起的特殊函数或方法。相比之下,普通的同步函数和方法只能持续运行到完成、抛出错误,或是永远不返回。异步函数或方法也能做到这三件事,但多出了等待其他资源时暂停执行的能力。在异步函数或者方法的代码块中,你需要明确标注这些可以暂停执行的位置。
5454

55-
要将一个函数或方法标记为异步,你需要在它的声明中的参数列表后边加上 `async` 关键字 —— 这和使用`throws` 关键字来标记可抛出错误的函数十分相似。如果你的函数或方法有返回值,你需要将 `async` 添加在返回箭头 (`->`) 的前面。比如,下面这段代码会从图库中提取照片名:
55+
要将一个函数或方法标记为异步,你需要在函数 / 方法签名的参数列表后边加上 `async` 关键字 —— 这和使用`throws` 关键字来标记可抛出错误的函数十分相似。如果你的函数或方法有返回值,你需要将 `async` 添加在返回箭头 (`->`) 的前面。比如,下面这段代码会从图库中提取照片名:
5656

5757
```swift
5858
func listPhotos(inGallery name: String) async -> [String] {
@@ -88,7 +88,7 @@ func listPhotos(inGallery name: String) async -> [String] {
8888
```
8989
-->
9090

91-
在调用异步方法时,当前方法的执行会被暂时挂起,直到被调用异步方法返回。你需要在调用前增加 await 关键字来标记此处为可能的挂起点(suspension point)。这就和在调用会抛出错误的方法前需要添加 `try` 一样 —— 为了标记在发生错误时,程序的执行流程可能发生变化。在一个异步方法中,方法 *只会* 在调用另一个异步方法时被挂起 —— 挂起永远不会是隐式或抢占式的,所有可能的挂起点都会用 `await` 明确地标注出来。这样一来,并发代码的可读性就获得了提升。
91+
在调用异步方法时,当前方法的执行会被暂时挂起,直到被调用异步方法返回。你需要在调用前增加 await 关键字来标记此处为可能的挂起点(suspension point)。这就和在调用会抛出错误的方法前需要添加 `try` 一样 —— 为了标记在发生错误时,程序的执行流程可能发生变化。在一个异步方法中,方法*只会*在调用另一个异步方法时被挂起 —— 挂起永远不会是隐式或抢占式的,所有可能的挂起点都会用 `await` 明确地标注出来。这样一来,并发代码的可读性就获得了提升。
9292

9393
举个例子,下面这段代码会读取图库中所有图片的名称,然后展示第一张图片:
9494

@@ -101,6 +101,7 @@ show(photo)
101101
```
102102

103103
<!--
104+
104105
- test: `defining-async-function`
105106
106107
```swifttest
@@ -136,7 +137,7 @@ show(photo)
136137

137138
6.`downloadPhoto(named:)` 返回后,它的返回值会被赋值到 photo 变量中,然后被作为参数传递给 `show(_:)`
138139

139-
代码中被 `await` 标记的挂起点表明当前这段代码可能会暂停等待异步方法或函数的返回。这也被称为 *让出线程(yielding the thread)*,因为在幕后 Swift 会挂起这段代码在当前线程的执行,转而让其他代码在当前线程执行。因为有 `await` 标记的代码可以被挂起,所以在程序中只有特定的地方才能调用异步方法或函数:
140+
代码中被 `await` 标记的挂起点表明当前这段代码可能会暂停等待异步方法或函数的返回。这也被称为*让出线程*,因为在幕后 Swift 会挂起这段代码在当前线程的执行,转而让其他代码在当前线程执行。因为有 `await` 标记的代码可以被挂起,所以在程序中只有特定的地方才能调用异步方法或函数:
140141

141142
- 异步函数,方法或变量的内部的代码
142143

@@ -529,13 +530,13 @@ task.cancel() // 输出 "Canceled!"
529530
a deadline is usually what you want anyhow when you think of a timeout
530531
531532
- this chapter introduces the core ways you use tasks;
532-
for the full list what you can do,
533-
including the unsafe escape hatches
534-
and ``Task.current()`` for advanced use cases,
535-
see the Task API reference [link to stdlib]
533+
for the full list what you can do,
534+
including the unsafe escape hatches
535+
and ``Task.current()`` for advanced use cases,
536+
see the Task API reference [link to stdlib]
536537
537538
- task cancellation isn't part of the state diagram below;
538-
it's an independent property that can happen in any state
539+
it's an independent property that can happen in any state
539540
540541
[PLACEHOLDER ART]
541542
@@ -749,7 +750,7 @@ extension TemperatureLogger {
749750

750751
上面这段代码会逐个转换数组内的测量数据。在 map 操作的执行过程中,有些温度还是华氏度,有些则已经转换为了摄氏度。但是,因为其中没有任何代码包含 `await`,这里不会出现潜在的挂起点。这个方法所修改的状态从属于 actor,actor 为这个状态提供了保护,使其免受不在 actor 上运行的代码的读取或修改。这意味着其它代码不可能有办法读取到单位转换过程中,只被转换了一半的测量数据。
751752

752-
除了将代码编写在一个 actor 中,并在其中舍弃掉所有的挂起点之外,还有更进一步的方式来避免出现临时性的不合法状态:将这些代码移动到一个同步方法中。上方的 `convertFahrenheitToCelsius()` 方法就是一个同步方法,保证了它*永远*不可能包含挂起点。这个方法封装了会暂时造成不合法数据状态的代码,从而使得阅读代码的人更容易意识到:在这个方法完整自己的任务、并将合法的数据状态被恢复之前,没有其它代码可以运行。在未来,如果你试图向这个方法中添加并发代码,或是一个可能的挂起点,编译器会及时报错,以防引入新 bug。
753+
除了将代码编写在一个 actor 中,并在其中舍弃掉所有的挂起点之外,还有更进一步的方式来避免出现临时性的不合法状态:将这些代码移动到一个同步方法中。上方的 `convertFahrenheitToCelsius()` 方法就是一个同步方法,保证了它*永远*不可能包含挂起点。这个方法封装了会暂时造成不合法数据状态的代码,从而使得阅读代码的人更容易意识到:在这个方法完成自己的任务、并将合法的数据状态被恢复之前,没有其它代码可以运行。在未来,如果你试图向这个方法中添加并发代码,或是一个可能的挂起点,编译器会及时报错,以防引入新 bug。
753754

754755
<!--
755756
OUTLINE

0 commit comments

Comments
 (0)