Swift

9. 프로세스와 스레드

Daesiker 2022. 8. 25. 15:49
반응형

9-1. 프로세스(Process)

  • 정의 : 운영체제로부터 시스템 자원을 할당받는 작업의 단위

프로세스는 프로세스 각각의 독립된 메모리를 할당받는다.

독립된 메모리 영역이기 때문에 프로세스끼리 서로의 변수에 접근을 할 수 없다.

멀티 프로세스(Multi-Process)

  • 정의 : 하나의 프로그램을 여러개의 프로세스로 구성하여 각 프로세스마다 하나의 작업씩 처리하는 방법
  • 장점
    • 서로 다른 프로세스가 독립된 메모리 영역을 할당받기 때문에 서로의 자원에 침투할 수 없음
    • 침투할 수 없으므로 안정성이 높음
  • 단점
    • 독림된 메모리를 가지고 있기 때문에 프로세스간 자원 공유가 어렵다.
    • 실행하는 프로세스가 바뀔때마다 Context Switching이 발생하여 CPU의 부담도 커지고 오버헤드가 발생하게 된다.

✽ Context Switching : CPU의 할당된 프로세스를 바꾸는 과정


9-2. 쓰레드(Thread)

  • 정의 : 한 프로세스 내에서 동작되는 여러 실행의 흐름

쓰레드는 프로세스가 아닌, 프로세스 내에서 동작되는 것이기 때문에 메모리 영역을 독립적으로 할당 받지는 못한다. 따라서 Code, Heap, Data 영역은 프로세스에 있는 자원을 공유하고 Stack 영역만 독립적으로 할당받을 수 있다.

멀티 쓰레드(Multi-Thread)

  • 정의 : 하나의 프로세스안에 여러개의 쓰레드로 구성하여 각 쓰레드마다 하나의 작업씩 처리하는 방식
  • 장점
    • 쓰레드간 Stack 영역을 제외한 나머지 영역을 공유하기 때문에 ContextSwitching이 빠르다
    • 작업을 실행할때 프로세스를 생성하여 자원을 할당하는 것이 아니라서 생성 / 종료 시간이 빠름
    • 통신 방법이 간단하다.
  • 단점
    • 한 개의 쓰레드가 실행 중일 때 다른 쓰레드가 접근하면 동기화가 되어서 자원 공유 문제가 생긴다.
    • 하나의 쓰레드에서 문제가 발생하면 전체 쓰레드가 영향을 받는다.

9-3. Sync vs Async

-동기(Synchronous)

동기 방식은 요청과 응답이 동시에 발생하여 한 작업이 끝나기 전에 다른 작업을 수행하지 못한다.

별도의 작업없이 소스코드를 작성하면 동기 방식이로 코드가 작동한다.

import Foundation

for _ in 0..<5 {
    print("첫번째")
}

for _ in 0..<5 {
    print("두번째")
}
// 첫번째
// 첫번째
// 첫번째
// 첫번째
// 첫번째
// 두번째
// 두번째
// 두번째
// 두번째
// 두번째

일반적으로 코드를 작성하면 첫번째 반복문이 끝난 후에 두번째 반복문이 실행된 것을 알 수 있다.

-비동기(Asynchronous)

비동기 방식은 반대로 요청에 대한 응답이 동시에 발생하지 않는 방식이다.

작업이 끝나지 않더라도 다음 작업을 실행할 수 있다.

import Foundation

DispatchQueue.global().async {
    for _ in 0..<5 {
        print("첫번째")
    }
}

DispatchQueue.global().async {
    for _ in 0..<5 {
        print("두번째")
    }
}

// 첫번째
// 두번째
// 첫번째
// 첫번째
// 두번째
// 두번째
// 첫번째
// 첫번째
// 두번째
// 두번째

Swift 내장함수인 DispatchQueue를 이용해서 비동기 방식으로 변경을 한뒤 다시 실행을 해보았다.

화면 결과와 같이 “첫번째"와 “두번째"가 뒤죽박죽 섞여 있는 것을 알 수 있다.

코드를 실행할때마다 결과값이 달라질 수 있다.


9-4 Serial vs Concurrent

-Serial

비동기, 동기 함수들을 하나의 작업(Task)이라고 생각해보자. Serial은 하나의 작업이 끝나기 전에 다른 작업을 할 수 없고 순차적으로 실행하는 방식이다.

import Foundation

//Task1
func start() {
    print("시작")
}

//Task2
func syncTask() {
    for _ in 0..<5 {
        print("동기 작업")
    }
}

//Task3
func asyncTask() {
    DispatchQueue.global().async {
        for _ in 0..<5 {
            print("비동기 작업")
        }
    }
}

//Task4
func end() {
    print("종료")
}

start()
syncTask()
asyncTask()
end()

// 시작
// 동기 작업
// 동기 작업
// 동기 작업
// 동기 작업
// 동기 작업
// 종료
// 비동기 작업
// 비동기 작업
// 비동기 작업
// 비동기 작업
// 비동기 작업

일반적인 코드는 Serial 방식으로 작동하는데 예제를 보면 총 4가지의 작업이 있고 동기 작업 3개 비동기 작업 1개가 있다.

  1. Task1이 실행된다
  2. Teask2가 실행된다
  3. Task3이 global Queue에 진입한다.
  4. Task4가 실행된다.
  5. global Queue에 담긴 Task3이 실행된다.

앞서 말했듯이 작업하나가 끝나기 전에 다른 작업이 수행하지 않으므로 뒤죽박죽 섞이지 않고 순차적으로 출력문이 나온걸 확인할 수 있다.

-Concurrent

Serial과 반대로 Queue에 들어온 작업들이 동시다발적으로 실행된다.

즉 한 번에 여러개의 Task가 실행된다.

let concurrentQueue = DispatchQueue.init(label: "customQueue", attributes: .concurrent)
concurrentQueue.sync  { print("시작") }
concurrentQueue.async { for _ in 0...5 { print("비동기") }}
concurrentQueue.sync  { for _ in 0...5 { print("동기") } }
concurrentQueue.sync  { print("종료") }

// 시작
// 동기
// 동기
// 비동기
// 비동기
// 비동기
// 동기
// 동기
// 비동기
// 비동기
// 비동기
// 동기
// 동기
// 종료

concurrent 방식으로 작동하는 커스텀 큐를 만든 뒤에 동기 작업 3개, 비동기 작업 1개를 넣어서 실행시켰다.

여러개의 Task가 한번에 실행되므로 동기 함수가 종료되지 않았는데도 비동기 함수가 진입해서 같이 실행되는 것을 확인할 수 있다.

 

참조
https://babbab2.tistory.com/63?category=831129
https://babbab2.tistory.com/64?category=831129
반응형

'Swift' 카테고리의 다른 글

11. Unit Test(1)  (0) 2022.12.09
10. 멀티 스레딩과 GCD  (0) 2022.12.04
8. [Swift] App’s Life Cycle(앱 생명주기)  (0) 2022.08.17
7.[Swift] View Life Cycle(UIKit, SwiftUI)  (0) 2022.08.09
6. Swift 프로퍼티의 종류  (0) 2022.08.03