ããã«ã¡ã¯ãã¬ã·ããµã¼ãã¹éçºé¨ã¨æè¡é¨å ¼åã®ã´ã¡ã³ãµã³(@vincentisambart)ã§ãã
Swift Concurrencyã«é¢ããä¸ç´ã®è¨äºãã¾ã å¤ããªãæ°ããã¦ããã®ã§ãããããè¨äºãæ¸ããã¨ã«ãã¾ããã
Swift Concurrencyã®ç解ãæ·±ããã人ã«ã¯WWDC21ã®ãSwift concurrency: Behind the scenesããããããã§ãããã®ãã¬ã¼ã³ã®ä¸ã§DispatchSemaphore
ãSwift Concurrencyã§ä½¿ãã¹ãã§ã¯ãªãã¨è¿°ã¹ããã¾ããã
Swift Concurrencyã«æä¾ããã¦ãããã¼ã«ãè¦ãã¨ãã»ããã©ãããã¾ãããã§ãæä¾ããããã®ã§ã»ããã©ãä½ããªãã§ããããï¼ã»ããã©ã使ãããå ´é¢ãå¤ãããã§ã¯ããã¾ããããè¯ãåå¼·ã«ãªãã¨æãã¾ãã
ã©ããããã¼ã«ãæ¨æºã§æä¾ããã¦ããã®ã§ããããï¼safe(å®å
¨ã«ä½¿ãããã®)ã¯actor
ãTask
ãTaskGroup
ãasync let
ãAsyncStream
ãCheckedContinuation
ããããã§ãããã
ã»ããã©èªä½ã®èª¬æãããã¨é·ããªãã®ã§ãä¸è¨ã¯ã»ããã©ãããç¨åº¦ç¥ã£ã¦ããåæã§æ¸ãã¦ãã¾ããã»ããã©ã®ã¡ã½ããåã¯ã»ããã©ã®èª¬æã§ãã¾ã«ä½¿ãããåããã«ããP
ã¨V
ã§ã¯ãªããDispatchSemaphore
ã使ã£ã¦ããwait()
(å¾
ã¤)ã¨signal()
(åå³ãéã)ã使ãã¾ãã
ã»ããã©ã®å¤ã0
以ä¸ã ã£ããwait()
ã次ã®signal()
ã¾ã§å¾
ã¤å¿
è¦ãããã®ã§ãå¾
ãããä»çµã¿ãããå¾
ããªãã¦è¯ãã¨ããåå³ãéãä»çµã¿ããå¿
è¦ã§ããSwift Concurrencyã®ããããã®ãã¼ã«ã§å®è£
ã§ããªããæ¤è¨ãã¦ã¿ã¾ãããã
actor
actor
èªä½ã§ã§ãããã¨ãè²ã
è¦ã¦ããä½ããå¾
ããããã¹ã¯ãªãããã§ã(ãã¸ã¼ã¦ã§ã¤ãã¯è«å¤)ã
ã¨ã¯ãããã»ããã©ã®ç¶æ ãæ£ããä¿ã¤ã«ã¯è¯ãããããã¾ãããå¥ã®ãã¼ã«ã¨åããã¦ãªãå½¹ã«ç«ã¦ãããããã¾ããã
TaskGroup
ãasync let
async let
ã®evolution proposalãè¦ãã¨ãTaskGroup
ã¨æ¯è¼ãã¦ç´¹ä»ããã¦ãã¦ã2ã¤ã®ã¦ã¼ã¹ã±ã¼ã¹ãä¼¼ã¦ãã¾ãï¼å¦çãããã¤ãã®åã¿ã¹ã¯ã«åãã¦ãæå¾ã«è¦ªã¿ã¹ã¯ãçµæãã¾ã¨ãã¾ããasync let
ã¯åã¿ã¹ã¯ã®æ°ãåçã«å¤ããããªããã©ãã£ã¨ä½¿ããããæãã§ãããã
ç¹å®ã®ã»ããã©ã®wait()
ã¨signal()
ãå¼ãã§ããã¿ã¹ã¯ã親åãå
å¼ã§ããã¨éããªãã®ã§ãTaskGroup
ã¨async let
ããã£ã¨è©³ãã調ã¹ãªãã¦ã2ã¤ã¨ãåãã¦ããªããã§ãã
AsyncStream
AsyncStream
ã®ç´¹ä»äºä¾ã¯åºæ¬çã«æ¢åã®Swift Concurrencyã使ããªãã³ã¼ããSwift Concurrencyã®ä¸çã«æã£ã¦ãã¾ããã¼ãããSwift Concurrencyã使ã£ã¦ã»ããã©ãä½ããã¨ãã¦ããã®ã§ãAsyncStream
ã¯åãã¦ããªãã®ã§ã¯ï¼ã¨æãããããã¾ããããããå°ãè¦ã¦ã¿ã¾ãããã
AsyncStream
ãAsyncSequence
ãªã®ã§ãéåæã«å¤ãé çªã«çã¿åºãã¾ãã次ã®å¤ãå ¥æããã«ã¯await
ã使ãå¿ è¦ãããã®ã§ãã»ããã©ã®wait()
ã«è¿ãããããã¾ããAsyncStream
ã¯ã¯ãã¼ã¸ã£ã¼ã渡ãã¦ä½æãã¾ãï¼AsyncStream { continuation in ... }
ãã¯ãã¼ã¸ã£ã¼ã«æ¸¡ãããAsyncStream.Continuation
ã®yield()
)ãsignal()
ã«å°ãä¼¼ã¦ããããããã¾ãã
wait()
ã¨signal()
ã®å®è£
ã«ä½¿ããããªãã®ãè¦ã¤ããã®ã§ãæ¬å½ã«å®è£
ã§ããã®ãã¾ãããå°ãããã¥ã¡ã³ããè¦ã¦ã¿ã¾ãããã
signal()
ã«ä½¿ããããªAsyncSequence.Continution.yield()
ã¯ä¸¦è¡ã§è¤æ°ã®ã¿ã¹ã¯ããå¼ãã§ãåé¡ãªãããã§ã(ãã®å ´åãå¤ãåãåºãããé åºãä¿è¨¼ããã¾ããã)ãAsyncStream.init(_:bufferingPolicy:_:)
ã®ããã¥ã¡ã³ã)ããæç²ï¼
The
AsyncStream.Continuation
received by the build closure is appropriate for use in concurrent contexts. It is thread safe to send and finish; all calls to the continuation are serialized. However, calling this from multiple concurrent contexts could result in out-of-order delivery.
ã§ãããæ®å¿µãªãããwait()
ã®å®è£
ã¯ã§ããªãããã§ãã並è¡ã§è¤æ°ã®ã¿ã¹ã¯ããAsyncStream
ã®æ¬¡ã®å¤ãawait
ãããã¨ã¯ã§ãã¾ãããAsyncStream.Iterator
ã®ããã¥ã¡ã³ãããæç²ï¼
This type doesnât conform to
Sendable
. Donât use it from multiple concurrent contexts. It is a programmer error to invokenext()
from a concurrent context that constends with another such call, which results in a call tofatalError()
.
ä¸è¨ã«æ¸ãã¦ããæç¹ã§å®éã®ã³ã¼ãã§åããã¨ãã¦ã使ãã¹ãã§ã¯ããã¾ããããéã³æè¦ã§è©¦ãã¦ã¿ã¾ãããIterator
ãSendable
ã§ãªãããã¿ã¹ã¯éã§å
±æã§ããªããã並è¡ã§è¤æ°ã®ã¿ã¹ã¯ããvar iterator = stream.makeAsyncIterator(); await iterator.next()
ããã¦ã¿ãããè¨è¿°ã®éãfatalError()
ãèµ·ãã¾ããã
_Concurrency/AsyncStreamBuffer.swift:253: Fatal error: attempt to await next() on more than one task
ãã®ãããä»åã®ã¦ã¼ã¹ã±ã¼ã¹ã«ã¯åãã¾ãããã¨ã¯ãããAsyncStream
ãæ¢åã®ã³ã¼ããSwift Concurrencyã®ä¸çã«æã£ã¦ããããã ãã®ãã¼ã«ã§ã¯ãªããã¨ãè¦ãããã¨æãã¾ãã
CheckedContinuation
CheckedContinuation
ã¨ã¯
AsyncStream
åæ§ãCheckedContinuation
ã¯æ¢åã®ã³ã¼ããSwift Concurrencyã®ä¸çã«æã£ã¦ããããã®ãã¼ã«ã¨ãã¦ããç´¹ä»ããã¦ãã¾ããã³ã¼ã«ããã¯ã使ã£ã¦ããã¡ã½ãããawait
ã§ããããã«ããããã®ãã¼ã«ã§ãããä»åã®ã¦ã¼ã¹ã±ã¼ã¹ã§ä½¿ããªãã§ããããï¼
CheckedContinuation
ã¯withCheckedContinuation(function:_:)
)(ã¨ã©ã¼ãçºçãããã¨ãããã°withCheckedThrowingContinuation(function:_:)
))ã使ã£ã¦ä½ããã¾ãã
ä¸çªã·ã³ãã«ãªã¦ã¼ã¹ã±ã¼ã¹ã¯ä»¥ä¸ã®ããã«hogeWithCallback
ãawait
ã§ããããã«ãããã¨ã§ãã
// `hogeWithCallback(_:)`ã`hoge(_:)`ã¨å½åãã¦ã大ä¸å¤«ã§ãã func hogeWithCallback(_ callback: () -> Void) { ... } func hoge() async { await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in hogeWithCallback { continuation.resume() } } }
éåæã®ã¿ã¹ã¯ãawait withCheckedContinuation
ã«æ¢ã¾ã£ã¦ãcontinuationã渡ãããã¯ãã¼ã¸ã£ã¼ãå®è¡ããã¦ãhogeWithCallback
ãå¼ã°ãã¾ããCheckedContinuation
ã®resume
ã¡ã½ãããå¼ã°ãããawait withCheckedContinuation
ã«æ¢ã¾ã£ã¦ããã¿ã¹ã¯ãåéãã¾ãã
ã»ããã©ã¯wait()
å´ã§await withCheckedContinuation
ããã¦ãsignal()
å´ã§continuation.resume()
ãå¼ã¹ããå®è£
ã§ããããããã¾ãããåæã«è¤æ°ã®ã¿ã¹ã¯ãå¾
ã¤å¯è½æ§ãããã®ã§ã1ã¤ã®CheckedContinuation
ã§ã¯è¶³ãã¾ããããCheckedContinuation
ã®é
åã使ãã°è¯ãã§ãããã並è¡ã§ãã¾ãã¾ãªã¿ã¹ã¯ããã¢ã¯ã»ã¹ããã¦ããã»ããã©ã®å
é¨ç¶æ
ã§ããé
åã¨å¤ã®æ£å½æ§ãä¿ã¤ã«ã¯actor
ãåãã¦ãããã§ãã
ã»ããã©ã®å é¨ç¶æ
ã§ã¯å®è£
ãã¦ã¿ã¾ããããç¶æ
ã¯ã¨ããããä¸è¨ã®èª¬æã«ãã£ãå¾
æ©ä¸ã®CheckedContinuation
ã®é
åã¨ã»ããã©ã®å¤ãå¿
è¦ã§ãã
actor ContinuationSemaphore { // å¾ æ©ä¸ã®ã¿ã¹ã¯ã®`CheckedContinuation`ã§ãã // ãã®`Void`ã¯ãã®`CheckedContinuation`ãå¤ãè¿ããªããã¨ã示ãã¾ãã // ãã®`Never`ã¯ãã®`CheckedContinuation`ã§ã¯ã¨ã©ã¼ãçºçããªããã¨ã示ãã¾ãã private var waiters: [CheckedContinuation<Void, Never>] = [] // ã»ããã©ã®å¤ã§ãã // `value`ãè² ã§ããã°ã`waiters.count == -value`ãä¿è¨¼ããã¾ãã private var value: Int init(value: Int) { // `DispatchSemaphore`åæ§ãåæå¤ãè² ã§ãã£ã¦ã¯ããã¾ããã assert(value >= 0) self.value = value } // ã»ããã©ã®æ£å½æ§ãä¿ããã¦ããã®ã確èªããã¡ã½ããã§ãã private func ensureValidState() { // ã»ããã©ã®å¤ãæ£ã§ããã°ãå¾ ã¤ã¿ã¹ã¯ãããã¹ãã§ã¯ããã¾ããã // ã»ããã©ã®å¤ãè² ã§ããã°ãå¾ ã¤ã¿ã¹ã¯ã®æ°ã`-value`åã§ããã¹ãã§ãã assert((value >= 0 && waiters.isEmpty) || (waiters.count == -value)) }
wait()
ä¸çªè¤éãªã®ãwait()
ã®å®è£
ã§ãã
ã³ã¼ãèªä½ãé·ãããã§ããªããã·ã³ãã«ã«ãè¦ãã¾ãããç¹å¥ãªãã¨ãèµ·ãã¦ãã¾ãã
func wait() async { value -= 1 // å¼ãç®å¾ã«å¤ã0以ä¸ã ã£ããå¾ ã¤å¿ è¦ãããã¾ããã if value < 0 { await withCheckedContinuation { continuation in waiters.append(continuation) ensureValidState() } } ensureValidState() }
ãã®å®è£ ã¯æ¬å½ã«å¤§ä¸å¤«ã§ããããï¼
await
ã使ããã³ã«å¶å¾¡ããã¼ãå¥ã®ã¿ã¹ã¯ã«ç§»ãå¯è½æ§ãããã¾ããwait()
ãå¼ã°ããæã«value
ã0
ã§ãwaiters
ã空ã£ã½ã ã£ãã®ãä»®å®ãã¾ãã1
ãå¼ãããvalue
ã-1
ã«ãªã£ã¦ãawait withCheckedContinuation
ãå¼ã°ãã¾ããããã§å¶å¾¡ããã¼ãå¥ã®ã¿ã¹ã¯ã«ç§»ãã¨ããããå¥ã®ã¿ã¹ã¯ãã»ããã©ã使ãã°ãvalue
ã-1
ãªã®ã«waiters
ã空ã£ã½ãªã®ã§ä¸æ£ç¶æ
ã§ãããâ¦
ã¾ããwithCheckedContinuation
ãasync
é¢æ°ãªã®ã«ã渡ãããã¯ãã¼ã¸ã£ã¼ãç´æ¥actorã®ããããã£waiters
ãå¤æ´ã§ãã¦ããã®ã¯åã«ã¨ã£ã¦å°ãä¸æè°ã§ããã
actorä¸ã§ã®ã¯ãã¼ã¸ã£ã¼ã®å¶éãæ´ãåºãã¦ã¿ã¾ãããã
actorä¸ã§ã®ã¯ãã¼ã¸ã£ã¼ã®å¶é
ç¹å®ã®actorã«ã¨ã£ã¦ãã¡ã½ãããé¢æ°ã¯ãã®actorã®isolatedãª(å¤ç«ãã)ç°å¢ã«å±ãããã©ããã§åºå¥ããã¾ãããã®actorã®isolatedãªç°å¢ã«å±ããã¡ã½ãããé¢æ°ã¯ä»¥ä¸ã®éãã§ãï¼
- actorã®ä¸é¨ã¨ãã¦å®è£
ããã¦ãã¦ã
nonisolated
ã§ãªããã®
actor MyActor {
func anyMethod() {}
}
- actorå¤ã§å®è£
ããã¦ããããactorãå¼æ°ã§åãåã£ã¦ããã®å¼æ°ã«
isolated
ãæè¨ããã¦ãããã®
actor MyActor {}
func someFunction(myActor: isolated MyActor) {}
éã«actorã®isolatedãªç°å¢ã«å±ããªãã¡ã½ãããé¢æ°ã¯ä»¥ä¸ã®éãã§ãï¼
- actorã®ä¸é¨ã¨ãã¦å®è£
ããã¦ããã
nonisolated
ã§ãããã®
actor MyActor {
nonisolated func anyMethod() {}
}
- actorå¤ã§å®è£
ããã¦ãããããã®actorã
isolated
å¼æ°ã§åãåã£ã¦ããªããã®
actor MyActor {}
func someFunction() {}
ä»åæ°ã«ãªã£ã¦ããwithCheckedContinuation
ãç¹å®ã®actorã®isolatedãªç°å¢ã«ãå±ãã¾ãããããã®withCheckedContinuation
ãactorã®isolatedãªç°å¢ã«å±ããã¡ã½ããããå¼ã°ãã¦ã¯ãã¼ã¸ã£ã¼ã渡ãããã®ã§ããã®ã¦ã¼ã¹ã±ã¼ã¹ã«ç¦ç¹ãå½ã¦ã¾ãããã
ç¾ç¶Swiftã®Concurrencyãã§ãã¯ãããã©ã«ãã§ç·©ãã®ã§ãStrict Concurrency Checkingãä¸çªå³ããè¨å®ãCompleteãã«ãã¦è²ã 試ãã¦ã¿ã¾ãããã
ã²ã¨ã¾ãã¯ä¸çªã·ã³ãã«ãªã±ã¼ã¹ãå¼ã°ããé¢æ°ãæ®éã§ãã(async
ã§ãªã)å ´åãè¦ã¦ã¿ã¾ãããã
func normalFunctionTakingClosure(block: () -> Void) {} actor MyActor { var value: Int = 0 func anyMethod() async { normalFunctionTakingClosure { value = 1 } } }
ä¸è¨ã®ã³ã¼ãã§self.
ãæè¨ããã«actorã®ããããã£ããã®ã¾ã¾ã¢ã¯ã»ã¹ãã¦ãä½ã®è¦åãåºã¾ãããå¼ã°ããé¢æ°ãasync
ã§ãªãã®ã§ãactorã®isolatedãªç°å¢ã§å®è¡ãããã®ã§åé¡ãèµ·ããå¿é
ã¯ããã¾ããã
async
é¢æ°ã§è©¦ãã¦ã¿ã¾ãããã
func asyncFunctionTakingClosure(block: () -> Void) async {} actor MyActor { var value: Int = 0 func anyMethod() async { await asyncFunctionTakingClosure { value = 1 } } }
ä¸è¨ã®ã³ã¼ãããã«ãããã¨ä»¥ä¸ã®è¦åãåºã¾ããactorã®isolatedãªç°å¢ã«å±ããªãasync
ã¡ã½ãããé¢æ°ã¯å¥ã®ç°å¢ã§å®è¡ããã¾ãã() -> Void
ã¯ç°å¢ã®å¢çç·ã渡ããªãã¨ã(block
ã®åã() async -> Void
ã«ããã¨ãã¦åãã§ã)
Non-sendable type
() -> Void
exiting actor-isolated context in call to non-isolated global functionasyncFunctionTakingClosure(block:)
cannot cross actor boundary
å®è¡ç°å¢éãã¿ã¹ã¯éã«ã¯ãã¼ã¸ã£ã¼ãéãããå ´åã@Sendable
ãã¤ããå¿
è¦ãããã®ã§è©¦ãã¦ã¿ã¾ãããã
func asyncFunctionTakingClosure(block: @Sendable () -> Void) async {} actor MyActor { var value: Int = 0 func anyMethod() async { await asyncFunctionTakingClosure { value = 1 } } }
ä¸è¨ã®ã³ã¼ãããã«ãããã以ä¸ã®ã¨ã©ã¼ã«ãªã£ã¦ãã¾ãã¾ããã
Actor-isolated property
value
can not be mutated from a Sendable closure
actorã¯isolatedãªç°å¢ã§å®è¡ããããã®ãªã®ã§ãããããã£ãå¥ã®ç°å¢ããã¢ã¯ã»ã¹ã§ãããisolatedã§ãªããªãã¾ãã
withCheckedContinuation
ã¯ä¸è¨ã®asyncFunctionTakingClosure
ã«ä¼¼ã¦ããããªã®ã«ãè¦åãªãã¯ãã¼ã¸ã£ã¼ããactorã®ããããã£ã«ã¢ã¯ã»ã¹ã§ãã¾ãã
withCheckedContinuation
ã®å®ç¾©ãè¦ã¦ã¿ãã¨ãã¯ãã¼ã¸ã£ã¼ã®åã«@Sendable
ãã¤ãã¦ãã¾ããããä¸æè°ãª@_unsafeInheritExecutor
ã¨ããã®ãã¤ãã¦ãã¾ãã
ãã®@_unsafeInheritExecutor
ã®å½±é¿ã§withCheckedContinuation
ãç¹å¥ãªæ¯ãèãããã¾ããasync
é¢æ°ã§ã¯ãããã®ã®ãactorããå¼ãã§ãå®è¡ç°å¢(executor)ãç¶æ¿ããã¾ãã渡ãããã¯ãã¼ã¸ã£ã¼ã@Sendable
ã§ããªã@escaping
ã§ããªãåãå®è¡ç°å¢ã®ã¾ã¾å®è¡ããã¾ãããã£ã¨è©³ãã説æã¯ãã¡ããã覧ãã ããã
注æï¼unsafe
ã®ã¤ãããã®ã¯ãªãªã¼ã¹ãããã³ã¼ãã§ä½¿ãå ´åã注æãå¿
è¦ã§ããUnsafeContinuation
ãå©ç¨ãããã¨ã¯ã§ãã¾ãããå®å
¨ãªCheckedContinuation
ã使ãã¹ãã§ãã@_unsafeInheritExecutor
ãåããã«ãããç¹å¥ãªæ¯ãèããããã®ã§ä¸è¬çãªéçºã«ããã¦ä½¿ãå¿
è¦ãåºããã¨ã¯ãªãã¨æãã¾ãã
好å¥å¿ãæºããããã ãã«è©¦ãã¦ã¿ããäºæ³éã以ä¸ã®ã³ã¼ãã§ä½ã®è¦åãåºã¾ããã
@_unsafeInheritExecutor func asyncFunctionInheritExecutorTakingNonEscapingClosure(block: () -> Void) async {} actor MyActor { var value: Int = 0 func anyMethod() async { await asyncFunctionInheritExecutorTakingNonEscapingClosure { value = 1 } } }
wait()
åã³
ä½è«ã¯ããã¾ã§ã«ãã¦ãContinuationSemaphore
ã®wait()
ã«æ»ãã¾ãããã
func wait() async { value -= 1 // å¼ãç®å¾ã«å¤ã0以ä¸ã ã£ããå¾ ã¤å¿ è¦ãããã¾ããã if value < 0 { await withCheckedContinuation { continuation in waiters.append(continuation) ensureValidState() } } ensureValidState() }
ãStrict Concurrency Checkingãã®å³ãããæ大ã®Completeã«ãã¦ããä¸è¨ã®ã³ã¼ãã§è¦åãåºã¾ããã
(æ£ç¢ºã«ã¯Xcode 14.0.1ã§macOSç¨ã«ãã«ãããã¨åºã¾ãããiOSç¨ã ã¨åºãªãããXcode 14.1ã ã¨macOSç¨ã§ãåºã¾ãããè¦åãåºãã®ã¯ãã°ã§ééããªãããã§ã)ã
æ¹ãã¦wait()
ãå¼ã°ããæã«value
ã0
ã§ãwaiters
ã空ã£ã½ã ã£ãã®ãä»®å®ãã¦å®è¡é ã追ã£ã¦ã¿ã¾ãã
- å®è¡ç°å¢ãactorã®ç°å¢ã«åãæ¿ããã¾ãã
- actorã®å®è¡ç°å¢ä¸ã§
value -= 1
ãif value < 0 {
ãå®è¡ããã¾ãã withCheckedContinuation
ãactorã«å±ããªãã¨ã¯ããã@_unsafeInheritExecutor
ãã¤ãã¦ããã®ã§å®è¡ç°å¢(executor)ãç¶æ¿ãããwithCheckedContinuation
ãå®è¡ããã¾ããwithCheckedContinuation
ã®å é¨ã®åããè¤éã§ãããç°¡åã«ã¾ã¨ãã¦ã¿ãã¨ãcontinuationãä½æããã¦ãactorã®å®è¡ç°å¢ã®ã¾ã¾ã¯ãã¼ã¸ã£ã¼ãå¼ã°ããããã§ããvalue -= 1
ã¨waiters.append(continuation)
ã®éactorã®å®è¡ç°å¢ãé¢ãã¦ããªãã®ã§ãæ£å½æ§ãä¿ãããã¯ãã§ãã
signal()
signal()
ã¯å²ã¨ã·ã³ãã«ã§ããå¾
ã£ã¦ãããã®ãããã°ãä¸çªåããå¾
ã£ã¦ããcontinuationãåãåºãã¦resume()
ãå¼ã³ã¾ãã
func signal() { value += 1 if value <= 0 { // é åã空ã£ã½ã®å ´åã`removeFirst()`ã«ãã£ã¦ç°å¸¸çµäºããããã // ãã®`if`ã®æ¡ä»¶ãæºãããã¦ãã¦`signal()`ãå¼ã°ããæç¹ã§ã¯valueã®å¤ã-1以ä¸ã®ã¯ããªã®ã§ã // å¾ æ©ä¸ã®ã¿ã¹ã¯ã1ã¤ä»¥ä¸ã ã£ãã¯ãã§ãã let waiter = waiters.removeFirst() // `waiters`ãã1ã¤ã®`CheckedContinuation`ãåãåºãã¦ãæ£ããç¶æ ãä¿ãããã¯ãã§ãã ensureValidState() // å¾ ã£ã¦ããã¿ã¹ã¯ãç¶è¡ã§ãã¾ãã waiter.resume() } ensureValidState() } }
å ¨ä½ã®ã³ã¼ã
ä¸è¨ã«ContinuationSemaphore
ã®å
¨ã¦ã®ã³ã¼ãã3ã¤ã«åãã¦è¼ãã¾ãããã念ã®ããã¾ã¨ãã¦è¼ãã¾ããæå¤ã¨çãã§ãã(æ£å½æ§ã®ç¢ºèªãæ¶ãã¨ãªããã)ã
actor ContinuationSemaphore { private var waiters: [CheckedContinuation<Void, Never>] = [] private var value: Int init(value: Int) { assert(value >= 0) self.value = value } private func ensureValidState() { assert((value >= 0 && waiters.isEmpty) || (waiters.count == -value)) } func wait() async { value -= 1 if value < 0 { await withCheckedContinuation { continuation in waiters.append(continuation) ensureValidState() } } ensureValidState() } func signal() { value += 1 if value <= 0 { let waiter = waiters.removeFirst() ensureValidState() waiter.resume() } ensureValidState() } }
注æäºé
ä¸è¨ã®ã³ã¼ãã¯å°ã試ããããç解ãæ·±ããã«ã¯è¯ãä¾ã ã¨æãã¾ããããã®ã¾ã¾ãããã¯ã·ã§ã³ã§ä½¿ãã®ãããããã§ãã¾ããããã¾ããã¹ãããã¦ããªããã¨ãé¤ãã¦ãã以ä¸ã®åé¡ãæªè§£æ±ºç¶æ ã§ãã
ContinuationSemaphore
ã解æ¾ãããæãwaiters
ãæ®ã£ã¦ããã°ä½ããã¹ãã§ããããï¼DispatchSemaphore
ã¯è§£æ¾æã®value
ãä½ææã«æ¸¡ãããvalue
ããä½ãã£ããå¼·å¶çµäºã§ãã
- ã¿ã¹ã¯ã®ãã£ã³ã»ã«ãã©ãæ±ãã¹ãã§ããããï¼
- æä¾ããã¦ããæ©è½ãéããã¦ãã¾ãã
wait()
ã«ã¿ã¤ã ã¢ã¦ããæå®ã§ããããã«ããã¨ããsignal()
ã«æ°åã渡ããããã«ããã¨ããå¤ãã®ã»ããã©ã®å®è£ ã«å ¥ã£ã¦ãããã©ããã«ã¯ãªããã¾ãã¾ãªæ©è½ãããã¾ãã
ãã£ã³ã»ã«ãæ±ãå ´åã注æãå¿
è¦ã§ããwait()
ãå¼ãã§ããã³ã¼ãããã£ã³ã»ã«ãæèããªããã°ããã£ã³ã»ã«ã®å½±é¿ã§wait()
ãçµããã¨ããã»ããã©ã«å®ããã¦ãããªã½ã¼ã¹ã使ããã®ãåéããã¦ããã°å°ãã¾ããTask
ããã£ã³ã»ã«ãããã¨ãã«wait()
ãthrow
ããããã«ããæ¹ãè¯ãããããã¾ããã
Task
(ãã¼ãã¹ã³ã³ãã³ã)
ãã¾ãã¾ãªãã¼ã«ãè¦ã¦ã¿ã¾ããããTask
ã®è©±ã¯ã¾ã ãã¦ãã¾ããã§ããããTask
ã¯ç¹å®ãªã¿ã¹ã¯ãçµããã®ãå¾
ã¤ãã¨ã¯ã§ãã¾ã(await task.value
)ãããã®Task
èªä½ãæ¢ããæ¹æ³ããªãããã§ã(ãã¸ã¼ã¦ã§ã¤ãã¯ãã¡ããè«å¤)ã
å
ã
Task
ã«é¢ãã¦ã¯ãã®æ°è¡ã ãã§çã¾ãã¤ããã§ããããTask
ã®ããã¥ã¡ã³ããæ¹ãã¦è¦ã¦ããèãããããã¸ã¼ã¦ã§ã¤ãã«ã¯å°ãä¼¼ã¦ããéªéãªæ¹æ³ãæãã¤ãã¾ãããå®è¡ãããTask
ããã£ã³ã»ã«ã§ããæ©è½ã¨sleepãããæ©è½ãå©ç¨ããã°â¦
ä¸è¨ã®ContinuationSemaphore
ã®CheckedContinuation
ã®ä½¿ãæ¹ãæ³å®ããããã®ã ã¨æãã¾ãã以ä¸ã®TaskSemaphore
ãããã§ãããã¾ããããåã®æ°ã¥ãã¦ããªãåé¡ãé ãã¦ããããããã¾ããããããã使ãæ¹ãããããã§ããªãã¨ã¯ãããåå¼·ã«ãªãå¾ãã®ã§ãã¨ããããèå³ãããæ¹ã®ããã«è¼ãã¦ã¿ã¾ããå
¨ä½ã®æ§æãCheckedContinuation
ã使ã£ããã¼ã¸ã§ã³ã«è¿ãã®ã§ã説æã¯å°ãªãã§ãã
actor TaskSemaphore { private var value: Int private var tasks: [Task<Void, Never>] = [] init(value: Int) { assert(value >= 0) self.value = value } private func ensureValidState() { assert((value >= 0 && tasks.isEmpty) || (tasks.count == -value)) } func wait() async { value -= 1 if value < 0 { let task = Task { // ãã£ã³ã»ã«ãããªãéãæ°¸é ã«sleepããã¾ã while !Task.isCancelled { // ã¿ã¹ã¯ããã£ã³ã»ã«ãããããéä¸ã ã£ãsleepãããçµããã¯ãã§ãã try? await Task.sleep(nanoseconds: 100_000_000_000 /* é©å½ã«100ç§ */) } } tasks.append(task) ensureValidState() await task.value } } func signal() { value += 1 if value <= 0 { let task = tasks.removeFirst() ensureValidState() task.cancel() // æ°¸é ã«sleepããã¦ããã¿ã¹ã¯ããã£ã³ã»ã«ãããã¨ã§èµ·ããã¾ãã } ensureValidState() } }
æå¾ã«
ãã®è¨äºããã²ã¨ã¤ã ãè¦ããã¨ããããæ¢åã®ã³ã¼ããSwift Concurrencyã®ä¸çãã使ããããã«ããã¨ç´¹ä»ããã¦ãããã¼ã«ã¯ä»ã®ã¦ã¼ã¹ã±ã¼ã¹ã§ãå©ç¨ã§ããå ´åãããã¨ãããã¨ã§ããããCheckedContinuation
ãAsyncStream
ãæåããSwift Concurrencyã使ã£ã¦ããã³ã¼ãã§ãå½¹ã«ç«ã¤å ´é¢ãããã¾ãã
ã¾ãããã¹ã¦ã®ãã¼ã«ãæ´ãåºãã¦ãã»ããã©ãå®è£ ã§ãã¾ããããç¾å¨åå¨ããæ¨æºã©ã¤ãã©ãªã®ãã¼ã«ã ãã§å®è£ ã§ããªããã®ãããã¨æãã¾ãã
ãã®è¨äºãèªãã§ãããçãããSwift Concurrencyã«å°ãã§ã詳ãããªã£ã¦ãããå¬ããæãã¾ãã