본문 바로가기

iOS/Concurrency

[Swift 5.5] Structured concurruency in swift | Concurrency

 

작년에 처음으로 WWDC 라는 것을 알게 됬고 여러 주제 중 modern concurrency(async/await,actor etc..) 소개 영상을 봤습니다. 영상에처 자꾸 Structured concurrency라는 말을 하는데 이 부분만 해석을 못하고 관련 개념이 안떠서 당황했었는데 이제서야 알게 됬습니다. 요기에 자세하게 있는데 이 글을 읽으며 알게 된 내용을 정리하고자 글을 작성하게 되었습니다.

 

 

Structured Concurrency

Concurrency system은 기본적인 툴을 제공합니다. 대부분은 지금 실행중인 threads는 새로 만들어진 thread와 concurrent 실행을 해야 합니다. shared system resource는 한정되어 있기에 Thread explosion을 방지하고자 다른 thread가 신호를 보내기 전 까지 기다릴 줄도 알아야 합니다.

 

priority 높은 task는 먼저 끝나야 합니다. 이 task를 빨리 끝내기 위해 thread의 우선순위를 확장하고 thread안에서도 task의 우선순위를 지정해야 합니다. 가장 최고의 방법은 첫 thread가 대가하기 전까지 두 번째 thread를 확장하지 않는 것입니다. 그리고 두번째 thread를 등록시킴으로 이 문제를 임시적으로 해결할 수 있습니다.

 

Structured concurrency는 이러한 문제를 programmer에게 high-level task와 이들의 child tasks로 구성한 concurrency 사용을 조작하도록 요청해서 해결합니다. 이 작업이 thread와 같은 low level의 개념보다 concurrency의 가장 기본 단위가 됩니다.

Concurrency를 structuring 하는 이 방법은 모든 추상적인 level, threads 전환에서 신중하게 작성된 자원을 필요로 하는 tasks의 계층 구조에서 정보가 자연스레 up, down으로 흐를 수 있습니다. 이는 많은 high-level의 문제를 해결할 수 있습니다.

Structured Concurrency Exemple

  • 보통 task의 수행시간을 제한합니다. timeout을 전달되는 것을 허용함으로 이를 지원해주는 APIs가 있습니다. 프로그래머가 timeout기간을 상대적으로 직접 정하기에 모든 level의 추상화를 통한 작업은 많은 시간을 소모합니다. 고로 Structured concurrency에서 task에 기한을 설정할 수 있어야 하고 임의의 level API를 통해 child tasks를 포함해서 자연스럽게 전파할 수 있어야 합니다.
  • Active중인 task를 취소할 수 있어야 합니다. asynchronously interface는 cancel()메서드를 통해 token 객체를 동기적으로 반환함으로 이를 지원합니다. token 전파, cancel을 API에 구성하는게 상당항 문제 생성될 수 있을만큼 cancel 설계는 복잡합니다. 몇 API는 이를 지원해주지 않습니다. (GCD에서 DispatchWorkItem는 취소를 지원합니다) Structured concurrency에서 cancel은 자연스레 API 덕에 child tasks로 전파되고, 헨들러를 통해 취소에 대한 action처리 가능해야 합니다.
  • GUI는 시기적절하게 refresh랑 이벤트 보장을 위해 task priority에 자주 의존합니다. Structured Concurrency에서 child tasks는 자연스래 이를 호출한 parent task의 우선순위를 상속받을 수 있어야 합니다. 만약 우선순위가 높은 task가 lower-priority tasks의 완료를 기다려야 하는 상황이라면 child tasks까지 우선순위를 올릴 수 있습니다.
  • 많은 시스템은 추상적인 level을 통해 pass하지 않은 채로 자신만의 contextural 정보를 유지하기 윈합니다. 그 예로 지금 서비스 중인 연결 정보를 서버에 기록하지 않는 것이 있습니다. Structured concurrency는 child tasks에서 선택할 수 있는 "task-local storage"로 async 작업을 통해 자연스레 전파될 수 있습니다.
  • 실제로 다룰 수 있는 work보다 많은 tasks를 받아들였을 때, Queue에 의존하는 시스템들은 queue-flooding에 자주 취약해 질 수 있습니다.  요런게 전형적인 "back-pressure"로 해결될 수 있습니다. 받아들여진 new task를 취소하고, queue에 task를 enqueue하려는 System 스스로가 응답받아 이 작업을 중단하도록 하는 작업인데 시스템 불안정해 질 수 있다고 합니다. Structured concurrency는 제한적, 협력적인 솔루션을 제공해야 합니다. system에서 곤란한 task 계층 구조와 소통을 통해 잠재적으로 parent task를 stop하거나 유사한 새로운 작업 생성을 느리게 만들 수 있도록 허용해야 합니다.

요런 느낌이 Structured concurrency이고 Swift 5.5 concurrency에선 async/awiat, task, child tasks, jobs, executor, task priorities 등이 이런 원식을 기반으로 설계 되었다고 합니다.

References

https://github.com/apple/swift-evolution/blob/main/proposals/0304-structured-concurrency.md