actor A {
var t = 1
func tt() -> Int {
for i in 0 ... 1000000 {
t += i
}
let s = t
t = 1
return s
}
}
var a = A()
var b = A()
func go() {
Task {
var d = Date()
await (a.tt(), b.tt())
print("time=1",d.timeIntervalSinceNow)
d = Date()
await a.tt()
await b.tt()
print("time2=",d.timeIntervalSinceNow)
d = Date()
async let q = (a.tt(), b.tt())
await q
print("time3=",d.timeIntervalSinceNow)
d = Date()
async let q1 = a.tt()
async let q2 = b.tt()
await q1
await q2
print("time4=",d.timeIntervalSinceNow)
d = Date()
async let q3 = a.tt()
async let q4 = b.tt()
await (q3, q4)
print("time5=",d.timeIntervalSinceNow)
}
}
$ xcrun swift -version
swift-driver version: 1.62.15 Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
Target: arm64-apple-macosx13.0
$ xcodebuild -version
Xcode 14.2
Build version 14C18
// Executed in playground
import Foundation
actor A {
func job(_ i: Int, _ d: Date) async throws -> Int {
try await Task.sleep(nanoseconds: UInt64(2) * NSEC_PER_SEC) // the number 2 can be changed
print("i=\(i) time spent = \(-d.timeIntervalSinceNow)")
return i
}
}
var a = A()
var b = A()
var d = Date()
func go() {
Task {
do {
// case 1 - non concurrent
print("case 1")
d = Date()
try await (a.job(11, d), b.job(12, d))
print("time spent case 1 = \(-d.timeIntervalSinceNow)")
// case 2 - non concurrent
print("case 2")
d = Date()
try await a.job(21, d)
try await b.job(22, d)
print("time spent case 2 = \(-d.timeIntervalSinceNow)")
// case 3 - non concurrent
print("case 3")
d = Date()
async let q3 = (a.job(31, d), b.job(32, d))
try await q3
print("time spent case 3 = \(-d.timeIntervalSinceNow)")
// case 4 - concurrent, 41 or 42 may be printed first
print("case 4")
d = Date()
async let q41 = a.job(41, d)
async let q42 = b.job(42, d)
try await q41
try await q42
print("time spent case 4 = \(-d.timeIntervalSinceNow)")
// case 4.1 - concurrent, 411 or 412 may be printed first
print("case 4.1")
d = Date()
async let q411 = a.job(411, d)
async let q412 = b.job(412, d)
try await q411
print("case 4.1 mid") //
try await q412
print("time spent case 4.1 = \(-d.timeIntervalSinceNow)")
// case 5 - concurrent, 51 or 52 may be printed first
print("case 5")
d = Date()
async let q51 = a.job(51, d)
async let q52 = b.job(52, d)
try await (q51, q52)
print("time spent case 5 = \(-d.timeIntervalSinceNow)")
// case 6 - non concurrent
print("case 6")
d = Date()
_ = (try await a.job(61, d), try await b.job(62, d))
print("time spent case 6 = \(-d.timeIntervalSinceNow)")
} catch {
print("error=\(error)")
}
}
}
go()
典型输出:
case 1
i=11 time spent = 2.1285619735717773
i=12 time spent = 4.261919021606445
time spent case 1 = 4.262814998626709
case 2
i=21 time spent = 2.1167279481887817
i=22 time spent = 4.234173059463501
time spent case 2 = 4.234648942947388
case 3
i=31 time spent = 2.1281230449676514
i=32 time spent = 4.263576984405518
time spent case 3 = 4.264067053794861
case 4
i=42 time spent = 2.130499005317688
i=41 time spent = 2.130929946899414
time spent case 4 = 2.131192922592163
case 4.1
i=412 time spent = 2.133057951927185
i=411 time spent = 2.13319993019104
case 4.1 mid
time spent case 4.1 = 2.133283019065857
case 5
i=51 time spent = 2.132704973220825
i=52 time spent = 2.133439064025879
time spent case 5 = 2.1337080001831055
case 6
i=61 time spent = 2.13224995136261
i=62 time spent = 4.265568017959595
time spent case 6 = 4.266121029853821
4条答案
按热度按时间6l7fqoea1#
如果您希望并发执行,请使用
async let
模式或任务组。你说:
但是下面的语句将并行运行do和stuff,对吗?
不,他们不会的。
以下经验最能说明这一点:
考虑下面的代码,使用元组方法:
以及:
这将产生一个图表,显示它不是同时发生的:
鉴于:
这会导致并发执行:
现在,在上面的例子中,我修改了函数,使它们返回值(因为这是使用元组有实际意义的唯一上下文)。
但如果它们不返回值,而您希望它们并行运行,则可以使用任务组:
这导致了它们并行运行的相同图形。
您也可以只创建
Task
示例,然后再创建await
示例:但是,当编译时可能不知道创建的任务数量时,任务组提供了更大的灵活性。
dnph8jn42#
看起来,为了获得并发执行,每个函数必须有一个显式的
async let
:打印输出:
ztmd8pv53#
基于gloo的回答,另一个测试使用睡眠作为耗时的工作。
环境
典型输出:
bxfogqkk4#
不,它们不是并行执行的。
首先,
是的简写语法
它是从左到右计算的,就像任何其他代码行一样。
现在,任何
await
调用都会挂起调用方的执行,如果被调用方挂起的话,这意味着只有在await do()
完成之后,await stuff()
才会继续执行。await
是一个挂起点(实际上是一个 * 可能的 * 挂起点),这意味着在await
完成之前,执行不会继续(无论是异步还是同步方式,都无关紧要)。我不知道如何检入Xcode,我的代码是并行运行还是顺序运行
除非你不信任编译器,否则你不需要这样做。从同一个
async
上下文(任务)派生多个await
的唯一方法是通过async-let
和TaskGroup
。但如果你真的想了解一下,出于学习的目的,其他人已经提供了一些有趣的方法,我只想留下我的方法,它与另一个已经提供的方法相似:
以上代码将生成以下输出: