You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Structured Programming는 구조화된 동시성이라는 개념을 사용해서 동시성 프로그램을 작성하는 새로운 방법을 소개합니다
기존에는 위와같은 control flow를 가지고 있어서 프로그램을 읽기가 어렵다는 단점이 존재했습니다
프로그램의 실행을 해석하기 위해서는 왔다갔다하면서 해석해야하는 문제가 발생하게된다
이게 사실 completion handler를 사용하는 비동기코드에서의 문제점으로도 지적되었다
하지만 요즘에는 Structured Programming을 사용하기 때문에 더 이상 이런 모양을 flow를 가지지 않습니다
if 블록을 통해 구조화된 프로그래밍을 사용할 수 있습니다
코드의 실행을 위 -> 아래로 이동하는 동안에만 조건부로 실행되도록 구조화가 가능해집니다
그리고 이러한 구조를 중첩하므로써 자연스럽게 순서를 지정하고 함께 중첩될 수 있습니다.
이것이 Structured Programming의 기초 입니다.
좋은 코드란 읽기쉬운코드라는 말이 있는것처럼 top down방식으로 여러 scope를 왔다갔다하며 읽고있습니다
그런데 문제는 단순히 순서대로 실행되는 앞선 task가 끝나야 뒷단의 task가 실행되는 그런 실행순서를 가질 수 없는것이 요즘의 프로그래밍입니다
왜냐면 요즘의 프로그래밍에서는 비동기적인 작업순서와 동시성이라는 특징을 항상 가지고있기때문입니다
애초에 비동기는 실행순서를 신경쓰지 않기 때문입니다
Structured Programming + asynchronous Code
meet async/await에도 나왔던 예제입니다
completion handler로 작성된 네트워킹 비동기 코드는 구조화된 제어흐름을 사용할 수 없습니다
이 코드를 structured programming을 기반으로 하는 async/await으로 바꿔보겠습니다
이렇게 사용하면 await을 만나 suspend되면서 함수자체가 structured한 control flow를 가지게 됩니다
기존에는 어떤 비동기 task가 실행되면 그 실행이 끝나고 결과값을 return한 뒤에 다음 statement를 실행헀습니다
물론 await 메서드가 실행ㅇ ㅣ시작되는 순간 os가 제어권을 가져가서 다른 급한 task를 처리할 수 있죠
하지만 여기서 이런 상황이 생깁니다
수 천개의 이미지에 대한 썸네일을 만들어야 하는 경우
썸네일을 고정 크기가 아닌 다른 URL에서 다운로드 해야 한다면 어떻게 해야할까요?
우리는 concurrency를 추가할 수 있으므로, 여러 다운로드가 병렬(parrel)로 발생할 수 있습니다.
우리는 프로그램에 Concurrency(동시성)을 추가하기 위해 Additional Task를 생성할 수 있습니다.
Async-let tasks
async let 바인딩이라는 가장 간단한 Task에 대해 알아보겠습니다
기존의 방식은 위와같은flow로 실행됩니다
여기서 let앞에 async를 붙여주면 async let 바인딩이 됩니다
async let의 경우 control flow가 아래와같습니다
우선 async let을 만나면 child task라는 subtask를 만들고 그 subtask안에서 오래걸리는 작업을 수행합니다 이때 이 수행이 끝나기를 기다리는것이 아니라 다음 task를 실행하고 실제로 subtask에 대한 결과를 사용할때 subtask의 수행이 끝나기를 기다립니다
애초에 실행시점에서 끝나기를 기다리는것이 아니라
실행결과를 실제로 사용하는곳에서 기다리면서 parent task는 다음 동작을 수행합니다
그리고 우리가 기존에는 오래걸리는, 비동기적으로 수행해야할 task앞에 await을 붙였는데 asnyc let binding에서는 실제로 사용하는 곳앞에 try await을 붙이면됩니다
어떤 task를 기다리는지에 따라 try await의 위치가 달라집니다
기존에 우리가 했던 async/await에서는 비동기메서드의 실행이 끝나기를 기다리고 그 return값을 넣는 변수 앞에다가 await을 붙였습니다
이 말은 그 메서드가 끝나기를 기다리겠다는 뜻이됩니다
이 경우에는 메서드 실행을 비동기적으로 수행하지만 실제로 사용하는 곳에서 await을 붙여서 결과값에 메서드의 값이 들어오기를 기다립니다
Structured task guarantees
하나의 Asynchronous 함수에서 다른 함수로 호출할 때 마다, 동일한 Task가 호출을 실행하는데 사용됩니다
Task는 특정 function의 child는 아니지만, 그들의 수명은 해당 function의 범위로 지정될 수 있습니다.
코드를 보면, data를 가져오는 다운로드를 먼저 시작했는데, metaData 작업부터 기다립니다
근데 만약 data를 다운로드하는데서 오류가 날수도 있습니다
Parent Task는 data에서 오류가 나도, metaData 작업을 그냥 취소 상태로 만들어버린다음 fetchThumbnail 함수가 끝날 때 까지 기다립니다
Task를 Cancel로 마킹해도 Stop 시키진 않습니다. 그냥 결과가 이제 필요하지 않다고 합니다
Cancellation is cooperative
Task는 cancel됐다고 바로 stop 하지 않습니다
cancellation은 어디서나 체크될 수 있습니다
API를 cancellation을 염두해두고 디자인해야합니다
결국 task는 error가 발생하면 cancel될수있고 그걸 추적하기 위해서 try Task.checkCancellation(), if Task.isCancelled등으로 task가 cancel된 것을 감지하여 무의미한 task실행을 하지 않습니다
Group Task
group task의 경우에는 어떤 loop를 돌떄 다음 loop가 이전 task블럭의 실행이 완료되어야할떄 사용됩니다
하지만 한번에 다운로드하고싶을수도있고 루프가 정말 많이 돈다면 문제가 발생하고 이를 해결하는것이 group task입니다
Task Group은 dynamic한 양의 concurrency를 제공하도록 설계된 structured concurrency의 한 형태입니다.
하지만 위와 같이 실행하면 한번에 딕셔너리에 접근해서 write를 하기때문에 data race가 발생합니다
Structured Programming
Structured Programming는
구조화된 동시성
이라는 개념을 사용해서 동시성 프로그램을 작성하는 새로운 방법을 소개합니다기존에는 위와같은 control flow를 가지고 있어서 프로그램을 읽기가 어렵다는 단점이 존재했습니다
프로그램의 실행을 해석하기 위해서는 왔다갔다하면서 해석해야하는 문제가 발생하게된다
이게 사실 completion handler를 사용하는 비동기코드에서의 문제점으로도 지적되었다
하지만 요즘에는 Structured Programming을 사용하기 때문에 더 이상 이런 모양을 flow를 가지지 않습니다
if 블록을 통해 구조화된 프로그래밍을 사용할 수 있습니다
코드의 실행을 위 -> 아래로 이동하는 동안에만 조건부로 실행되도록 구조화가 가능해집니다
그리고 이러한 구조를 중첩하므로써 자연스럽게 순서를 지정하고 함께 중첩될 수 있습니다.
이것이 Structured Programming의 기초 입니다.
좋은 코드란 읽기쉬운코드라는 말이 있는것처럼 top down방식으로 여러 scope를 왔다갔다하며 읽고있습니다
그런데 문제는 단순히 순서대로 실행되는 앞선 task가 끝나야 뒷단의 task가 실행되는 그런 실행순서를 가질 수 없는것이 요즘의 프로그래밍입니다
왜냐면 요즘의 프로그래밍에서는 비동기적인 작업순서와 동시성이라는 특징을 항상 가지고있기때문입니다
애초에 비동기는 실행순서를 신경쓰지 않기 때문입니다
Structured Programming + asynchronous Code
meet async/await에도 나왔던 예제입니다
completion handler로 작성된 네트워킹 비동기 코드는 구조화된 제어흐름을 사용할 수 없습니다
이 코드를 structured programming을 기반으로 하는 async/await으로 바꿔보겠습니다
이렇게 사용하면 await을 만나 suspend되면서 함수자체가 structured한 control flow를 가지게 됩니다
기존에는 어떤 비동기 task가 실행되면 그 실행이 끝나고 결과값을 return한 뒤에 다음 statement를 실행헀습니다
물론 await 메서드가 실행ㅇ ㅣ시작되는 순간 os가 제어권을 가져가서 다른 급한 task를 처리할 수 있죠
하지만 여기서 이런 상황이 생깁니다
우리는 concurrency를 추가할 수 있으므로, 여러 다운로드가 병렬(parrel)로 발생할 수 있습니다.
우리는 프로그램에 Concurrency(동시성)을 추가하기 위해 Additional Task를 생성할 수 있습니다.
Async-let tasks
async let 바인딩이라는 가장 간단한 Task에 대해 알아보겠습니다
기존의 방식은 위와같은flow로 실행됩니다
여기서 let앞에 async를 붙여주면 async let 바인딩이 됩니다
async let의 경우 control flow가 아래와같습니다
우선 async let을 만나면 child task라는 subtask를 만들고 그 subtask안에서 오래걸리는 작업을 수행합니다 이때 이 수행이 끝나기를 기다리는것이 아니라 다음 task를 실행하고 실제로 subtask에 대한 결과를 사용할때 subtask의 수행이 끝나기를 기다립니다
애초에 실행시점에서 끝나기를 기다리는것이 아니라
실행결과를 실제로 사용하는곳에서 기다리면서 parent task는 다음 동작을 수행합니다
그리고 우리가 기존에는 오래걸리는, 비동기적으로 수행해야할 task앞에 await을 붙였는데 asnyc let binding에서는 실제로 사용하는 곳앞에 try await을 붙이면됩니다
어떤 task를 기다리는지에 따라 try await의 위치가 달라집니다
기존에 우리가 했던 async/await에서는 비동기메서드의 실행이 끝나기를 기다리고 그 return값을 넣는 변수 앞에다가 await을 붙였습니다
이 말은 그 메서드가 끝나기를 기다리겠다는 뜻이됩니다
이 경우에는 메서드 실행을 비동기적으로 수행하지만 실제로 사용하는 곳에서 await을 붙여서 결과값에 메서드의 값이 들어오기를 기다립니다
Structured task guarantees
하나의 Asynchronous 함수에서 다른 함수로 호출할 때 마다, 동일한 Task가 호출을 실행하는데 사용됩니다
Task는 특정 function의 child는 아니지만, 그들의 수명은 해당 function의 범위로 지정될 수 있습니다.
코드를 보면, data를 가져오는 다운로드를 먼저 시작했는데, metaData 작업부터 기다립니다
근데 만약 data를 다운로드하는데서 오류가 날수도 있습니다
Parent Task는 data에서 오류가 나도, metaData 작업을 그냥 취소 상태로 만들어버린다음 fetchThumbnail 함수가 끝날 때 까지 기다립니다
Task를 Cancel로 마킹해도 Stop 시키진 않습니다. 그냥 결과가 이제 필요하지 않다고 합니다
Cancellation is cooperative
Task는 cancel됐다고 바로 stop 하지 않습니다
cancellation은 어디서나 체크될 수 있습니다
API를 cancellation을 염두해두고 디자인해야합니다
결국 task는 error가 발생하면 cancel될수있고 그걸 추적하기 위해서
try Task.checkCancellation()
,if Task.isCancelled
등으로 task가 cancel된 것을 감지하여 무의미한 task실행을 하지 않습니다Group Task
group task의 경우에는 어떤 loop를 돌떄 다음 loop가 이전 task블럭의 실행이 완료되어야할떄 사용됩니다
하지만 한번에 다운로드하고싶을수도있고 루프가 정말 많이 돈다면 문제가 발생하고 이를 해결하는것이 group task입니다
Task Group은 dynamic한 양의 concurrency를 제공하도록 설계된 structured concurrency의 한 형태입니다.
하지만 위와 같이 실행하면 한번에 딕셔너리에 접근해서 write를 하기때문에 data race가 발생합니다
이런상황을 위해 @sendable이라는 개념이 필요해집니다
Task의 생성은 @sendable 클로저에서 실행됩니다
그러면 data race를 방지할 수 잇습니다
Unstructured Task
Task가 항상 명확한 계층 구조에 속한식으로만 구현되진 않습니다.
오히려 훨씬 더 많은 수동관리가 필요한 대신 유연성을 제공하는 Unstructured한 방식이 더 많습니다
CollectionViewCell에 네트워크에서 가져온 썸네일을 가져와 띄우려고 합니다.
하지만 Delegate 메서드는 async 하지 않기 때문에 async 함수를 호출할 수 없습니다.
MainThread에서 동작하기 때문에 await할 수 없기 때문이죠
우리가 Delegate 메서드 안에서 Task 를 생성한다면, 우리는 이 Task가 Main Actor에서 실행되길 원합니다.
이 코드를 unstructured Task를 사용해 async 처리를 할 수 있게할 수잇습니다
그렇게 되면 async관련 처리를 task안에 넣으면 위 그림의 아래와같은 상황이 일어납니다
Task를 생성하는 시점에 도달하면 Swift는 original scope와 동일한 Actor에서 실행되도록 스케줄링 합니다. (Task는 자동으로 스케줄링)
이 경우에는 MainActor에서 실행되겠죠?
썸네일을 받아오는 Task는 Delegate 함수 안에서 Main Thread를 차단하지 않고 기회가 있을 때 Main Thread에서 실행됩니다.
이런식으로 Task를 실행하면 구조화된 코드와 구조화 되지 않은 코드 사이의 중간지점을 제공할 수 있습니다.
Detached Tasks
위에서 살펴본 Task는 모두 Task는 모두 생성되면 original scope의 특성을 상속하는 특징이 있었는데요 아무것도 상속하고 싶지 않은 독립적인 Task도 있습니다.
서버에서 썸네일을 가져온 후 나중에 가져오려고 할 때 네트워크에 다시 연결되지 않도록 로컬 디스크 캐시에 기록하려고 한다고 가정해보면
캐싱은 메인 액터에서 발생할 필요가 없으며 모든 썸네일 가져오기를 취소하더라도 가져온 썸네일을 캐시하는것이 여전히 유용할수있습니다
The text was updated successfully, but these errors were encountered: