Swift에서 멀티스레드로 함수를 실행하고 완료시 다른함수 호출하기
Function(Function()) 과 같은 아주 괴랄한 형태의 함수를 만들어보았다.
Swift에서는 싱글톤이나 자주 사용하는 클래스나 함수를 만들때 유용하게 사용할 수 있다.
Escaping을 통해 부모함수에 자식함수를 입력할 수 있도록 조치하고,
DispatchGroup을 통해 부모함수를 실행하되, Semaphore를 통해 쓰레드 제어를 한다.
부모함수가 실행이 완료되면, Dispatch된 함수의 Notify를 이용하여 자식함수를 실행한다.
자식함수는 Void형태의 변수로 담아두고 부모함수를 선언할때 해당 변수를 매개변수로써 실행해주면 된다.
아래는 소스코드
//자식함수(나중에 실행될 함수)
let input_func = {
print("WooooooooooOW")
}
//부모함수(먼저 실행되는 함수)
func test(_ functions: @escaping () -> Void){
let group = DispatchGroup() //Dispatch생성
let semaphore = DispatchSemaphore(value: 4) //Semaphore를 통해 총 4개의 동시작업
//테스트를 위한 반복문
for i in 1...5 {
//비동기로 실행
DispatchQueue.global().async(group: group) {
//쓰레드 시~~~작
semaphore.wait()
//쓰레드 종료!
defer { semaphore.signal() }
print("진행중: \(i)" )
//테스트를 위해 3초간 쓰레드 휴식
Thread.sleep(forTimeInterval: 3)
print("진행중(3초뒤): \(i)" )
}
}
//부모함수가 모두다 실행되었을때
group.notify(queue: DispatchQueue.main) {
//매개변수로 입력한 자식함수를 실행
functions()
}
}
//위의 괴랄한 함수를 실행!
test(input_func)
Semaphore의 간단하고 손쉬운 그림설명이다.
세마포어가 4개로 선언된다면 아래와 같이 4개의 테스크가 동시에 실행된다.
Wait -> 실행 -> Signal
Swift에서는 세마포어를 아래와 같이 선언하여 사용할 수 있다.
세마포어를 사용하는 이유는 parallel 한 동시적인 연산이나 작업을 실행하는것에 있어서 다른 작업과 공유자원을 활용하지 않도록 하기위함도 있다.
DispatchQueue.main도 있고 DispatchQueue.global등이 있지만, 앱을 개발하다보면 DispatchQueue가 무쟈게 많아진다 ㅠ
아래 예시코드터럼 총 4개의 세마포어를 선언하면 4개의 테스크를 동시실행할 수 있다. (실제로는 동시실행은 아니지만 동시실행처럼 실행된다.)
let semaphore = DispatchSemaphore(value: 4)
세마포어를 시작을 알리는 코드이다.
이 코드 아래부터는 임계구역안에서 실행되며, 동시작업할 코드들의 내용이 시작된다.
(이것을 실행하기 전에는 세마포어의 값이 감소되면서 세마포어가 시작된다.)
semaphore.wait()
아래 코드는 세마포어를 종료하는 코드이다.
defer는 해당 함수의 가장 마지막에 실행할 수 있도록 한다.
단, defer는 중간에 throw나 guard가 사용되어 함수가 종료될경우 defer는 실행되지 않음으로 유의해야한다.
defer { semaphore.signal() }