brunch

You can make anything
by writing

C.S.Lewis

by Tilltue Jun 04. 2021

Swift의 lazy var

lazy var ,  global var, Type Properties

Swift Document의 Properties의 lazy var를 설명하는 부분에 note 가 있다.

Swift의 lazy var는 멀티 thread에서 접근시 이니셜라이즈가 한번 불릴것을 보장하지 않다는 내용이다.



의문의 시작은 이렇다..


Kotlin In Action 책을 읽다가 아래와 같은 내용을 알게 됐고 Kotlin에서는 기본적으로 lazy 함수는 스레드 안전하고 필요에 따라 동기화가 필요 없는 lazy 함수를 사용할 수 있다는 것이다.

( kotlin lazyinit 은 그 성격이 다르므로 논외 )

Kotlin In Action 책 (번역본 p.334) 발췌



 왜 Swift는 lazy var를 thread safe 하지 않게 만들었을까?



먼저 개인적인 경험에 대한 이야기이다.


lazy var에 대해 처음 알게 되었을 때 "초기화에 비용이 많이 들 때 사용해야겠다"라고 생각하고 thread safe 하지 않다는 내용은 주의 깊게 보지 않았었다 =_=;; ( 멍청이... )


그러다 한번 동시성 환경에서 접근 시 crash를 경험하고, "어이쿠... 노트 자세히 볼걸..."라고 생각하고 완전히 단일 스레드에서 lazy var에 접근하는 것을 보장할 수 없는 상황에서는 lazy var를 쓰면 안 되겠구나 생각했다. 사실... 이후로는 거의 사용하지 않게 된 것 같다. ( 이전에도 따지고 보면 비용이 크게 드는 것도 사실 없는데 그냥 느낌적인 느낌으로 썼던 거라... ㅋ)


그런데 Kotlin 책을 읽고 왜 Swift는 이렇게 만들지 않은 거지? Kotlin 이후에 나온 거라 영향을 많이 받았을 텐데??라는 의문이 들었다. 그래서 찾아보게 됐다.


먼저 swift.org에서 찾은 내용이다. ( thread safe 한 lazy var를 만들어 달라는 내용 )

( 관련 이슈 SR-7712는 lazy var 가 thread safe 하지 않은 것을 간과한 이슈)


이 의견에 대해 댓글에서도 찬반이 있었다.


반대 의견 : 스레드로부터 안전한 lazy var는 일부 아키텍처에서 모든 읽기에 대해 메모리 장벽이 필요하다. 혹은 동기화를 위한 추가 공간이 필요하다. 이 두 가지 모두 비용이 비싸며 모든  lazy var에 적합하지 않을 수 있다.


찬성 의견 :  "lazy" 키워드의 동작은 동시성 프로그래밍을 할 때 lazy를 사용하는 것을 안티 패턴으로 보게 만든다. 그리고 thread safe 한 지연 초기화를 위한 커스텀 방법은 복잡하니 컴파일러에서 제공해줬으면 한다.


음 둘 다 일리 있어 보인다. 더 찾아보자.




forums.swift.org 에도 비슷한 제안이 있었다.  

( swift 2 시절에 나온 제안이다. 이걸 보니 앞으로도 추가될 일은 없겠다는 생각이 든다. ㅎㅎ)


글 안에도 장점과 단점에 대해 이야기하며 내용은 위의 찬성 반대 의견과 비슷하다.




두 파트에 걸쳐 글을 쓴 사람도 있다.

https://trinhngocthuyen.github.io/posts/tech/swift-the-downsides-of-lazy-var-part-1/

https://trinhngocthuyen.github.io/posts/tech/swift-the-downsides-of-lazy-var-part-2/

thread-safe 관련 이야기는 파트 2에  언급된다.


본문에 lazy var를 thread-safe 하게 구현한 방법에 대한 코드도 있다. 퍼포먼스 체크한 내용은 제외하고 발췌했다.

https://gist.github.com/tilltue/09a3902957ddf1bfc88f4b671289fe54



swift lazy var 설계 이력을 알고 싶었지만 찾지는 못했다.


특별한 키워드도 붙지 않은 lazy var 또한 일반 var 와 같이 똑같은 변수이므로 동기화를 보장하는 않는 것이 맞다고 생각한게 아닐까 싶다. ( 주변 지인이 이렇게 이야기 해줌 )


어쨌든 일부 사람들은 lazy var 가 thread safe 한 형태로도 제공되기를 원하는 것 같다.

개인적으로는 나도 Kotlin처럼 옵션이 다양하면 좋겠다고 생각한다.




Swift에서 글로벌 변수는 지연 초기화되며 Thread safe 한가?
static var 도 thread safe 한가?



궁금하구먼... 찾아보자.

운좋게 좋은 글을 찾았다.

글로 별 변수는 지연 초기화되고 한번만 초기화 되는 것을 보장한다.

Type Property ( static 키워드 사용 ) 또한 지연 초기화되고 멀티스레드에서 접근할때에도 한번만 초기화 된다는 내용이다.


위 글 본문에서 발췌한 관련 apple 문서에 구현에 대한 이야기가 나온다.

Atomicity 개념과 thread safe의 개념은 다르다는 것을 이야기한다.

Programming with Objective-C archive documentation에서 발췌된 내용

Atomicity (원자성) 은 변수의 읽고 쓰기의 무결성을 설명한다는 것


Swift의 글로벌 let과 static let는 원자적이고 불변하므로 thread safe 하다고 말할 수 있다.

글로벌 var와 static var의 경우 초기화 후 스레드에서 변경될 수 있으므로 thread safe 하다고 주장하긴 힘들다.


* Joe Groff : Senior Swift Compiler Engineer at Apple 가 확인해줬다고 한다.




kotlin 책을 읽다가 호기심에 찾아보게 되었는데 어쩌다 보니 여기까지 와버렸다. ( 머엉... )

여러 이야기들을 보게 되서 재밌었고 유익했다. 찾아본 시간이 헛되지 않은 것 같아 다행 :D


마침.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari