티스토리 뷰

반응형

 

스레드의 동시 접근으로 생기는 문제점인 Data Races 문제를 해결하기 위해서 사용할 수 있는 프로토콜이 있습니다.
Swift Concurrency 관련해서 생긴 새로운 타입인 Actor도 이 protocol을 채택하고 있는데요.

오늘은 Sendable protocol 문서를 읽어보고자 합니다. Sendable protocol의 요약 설명을 보면, 복사에 의해 Concurrency 도메인 간에 값을 안전하게 전달할 수 있도록 한다고 하는데, 문서를 보도록 하겠습니다.

 

 


동시성 문제를 해결하는 Actor와 Sendable protocol의 관계

하나의 스레드에서 동시 접근을 해버리면 예기치못한 동작을 야기할 수 있습니다. 대표적인 예사가 은행송금 문제입니다. 만약에 잔고가 100만원이 있는데, 동시에 100만원 출금 요청이 들어왔을때 동시 접근이 허용되어버리면, 100만원을 2번 출금해서 -100만원이 되어버릴 수도 있습니다.

이런 문제를 data races 문제라고 하는데요, 이를 해결하기 위해서는 두번의 출금 요청이 이루어지더라도, 스레드의 동시 접근이 되지 않도록 해서 2번째 접근 시에는 잔고가 없으므로 출금을 할 수 없도록 해야할 것입니다.

그럴때 사용할 수 있는 타입이 Actor입니다. Actor는 Class와 유사하나, 상속을 허용하지 않고, 내부에서 변경을 하고자 할때에는 async await 키워드를 사용해야합니다. 만약 변경이 필요하지 않는 함수의 경우에는 별도로 nonisolated func 과 같은 키워드 명시를 해주어야 하고요. 이를 통해서 data races 문제를 해소합니다.

이런 actor가 채택하고 있는 protocol이 바로 Sendable입니다.

 


Overview

Sendable protocol을 사용하면 동시성을 사용하는 하나의 도메인에서 다른 곳으로 값을 안전하게 전달할 수 있다고 합니다. 
Sendable protocol은 직접적으로 명시하지 않더라도, 다양한 경우에 암시적으로 적용이 된다고 합니다.

- enum, struct 같은 Value types
- 변경가능한 저장소가 없는 reference types
- 내부적으로 상태를 접근하고 관리하는 reference types
- @Sendable 명시가 된 function, closures

Sendable 프로토콜를 준수하기 위한 메서드, 프로퍼티 정의 요구사항이 없어보이는데요, 실제로는 컴파일 타임에 의미있는 요구사항을 갖고 있다고 합니다. 위와 같이 컴파일러에서 강제해서 Sendable을 준수하도록 하는 경우가 있지만, 만약 수동적으로 준수하고 싶다면, @unchecked Sendable 을 작성할 수 있습니다. 

 


Sendable Structures and Enumerations

개요에서 보았듯이, 아래와 같은 struct, enum value type들은 Sendable protocol을 준수하고 있습니다.

- Frozen struct, enum 들
- @usableFromInline을 명시하지 않고, public이 아닌 struct, enum 들

struct나 enum같은 value type이더라도, 위와 같은 케이스가 아니라면, 개발자가 Sendable 선언을 암시적으로 해주어야 합니다.

만약 nonsendable 저장 프로퍼티를 가졌거나, nonsendable 연관값을 같고 있는 enum이 존재한다면, @unchecked Sendable이 적용될 수 있습니다. 이 경우에는 컴파일 타임의 체크를 무효화 하고, 수동적으로 그들이 Sendable protocol의 요구사항을 준수하는지 확인해야할 수 있습니다.

 

 


Sendable Actors

앞서 보았듯이, 모든 actor type들은 기본적으로 Sendable protocol을 준수하고 있습니다. actor type의 기본적인 개념이 내부적으로 생기는 변경사항이 모두 순차적으로 진행되도록 보장하기 때문입니다.

 


Sendable Classes

class도 예외적인 경우에 Sendable protocol의 요구사항을 충족할 수 있는데요, 그 케이스는 아래와 같습니다.

- final class
- 변경되지 않고, sendable한 저장 프로퍼티만 포함한 경우
- superclass가 없거나, NSObject를 superclass로서 상속받는 경우
- @MainActor로 정의된 class들, @MainActor는 class의 상태들을 관리해주기 때문에, 이 경우에는 변경 가능하고, nonsendable한 저장프로퍼티를 가질 수도 있습니다.

만약 위 케이스가 아닌 class라면, @unchecked Sendable로 간주됩니다. 다른 @unchecked Sendable들 처럼 Sendable protocol을 준수하고 싶다면 수동적으로 판별을 해주어야 합니다.

 


Sendable Functions and Closures

Sendable protocol을 준수하는 방법 대신, @Sendable attribute를 사용해서 function, closure 들을 Sendable 하게 사용할 수 있습니다. Sendable한 function, closure 내에서 캡쳐되는 value 들은 Sendable type이어야 합니다. Task.detached(priority:operation:) 과 같은 closure는 암시적으로 Sendable protocol을 준수하고 있기도 합니다. 

만약 function이나 closure를 Sendable하게 사용하고 싶다면, 아래처럼 closure parameter 앞 등에 @Sendable을 명시해서 사용할 수 있습니다.

let sendableClosure: ((Bool) -> String) = { @Sendable flag in
    if flag {
        return "is ture"
    } else {
        return "is false"
    }
}

 


Sendable Tuple을 사용하려면..

Tuple을 사용할때 Sendable protocol의 요구사항 충족을 위해서는 Tuple에 사용되는 모든 타입들이 Sendable해야합니다. 만약 Tuple에 사용되는 모든 값들이 Sendable하다면, 암시적으로 해당 Tuple또한 Sendable protocol을 충족하게 됩니다.

 


Sendable Metatypes

Int.type과 같은 메타타입들은 암시적으로 Sendable protocol을 준수하고 있습니다. (Int.type 말고, 또 다른 Sendable metatype은 없는지 확인해봐야겠네요..)

 


Swift 5.5 부터 사용 가능한 Swift Concurrency의 Task, actor type을 활용하고자할때 사용되는 핵심적인 기능이 Sendable protocol인데요, Swift Concurrency 활용을 위해서는 관련해서 꾸준한 공부가 필요할 것 같습니다.

오늘은 Swift Concurrency의 개념 중 하나인 Sendable protocol의 개요에 대해서 알아보았습니다. 잘못된 번역, 설명이 있다면 피드백 부탁드립니다. 감사합니다. 🙏🏻

 

Reference

 

Sendable | Apple Developer Documentation

A type whose values can safely be passed across concurrency domains by copying.

developer.apple.com

 

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함