동기처리와 비동기처리. 직렬과 동시처리를 곁들인

Donghee Lee·2022년 3월 21일
1

iOS-Swift

목록 보기
11/20
post-thumbnail

동기처리와 비동기처리


JSON 타입으로 된 정보를 Alamofire를 사용하여 비동기로 Request 하며 학습한 내용입니다.
비동기처리 관련 학습글을 꾸준히 갱신 할 예정입니다.
부족한 내용이나 틀린 내용이 있다면 지적해주시면 감사하겠습니다.


동기처리와 비동기처리의 차이점

동기처리란?

직렬로 일을 수행하는 프로세스로 이해하면 된다.
한 줄의 프로세스 시퀀스가 있다면 순서대로 처리를 진행한다.
예를 들면

UI 변경 -> 네트워크 통신 -> 다른 일

이런식으로 진행하게 된다.

개념

Main Thread 에서 Task 1을 Thread 2에게 전달한다.

Main Thread의 Task 1이 차지하고 있던 영역은 '블로킹 처리' 되어

Thread 2가 Task 1을 처리할 때까지 "기다린다"

비동기처리란?

병렬로 일을 수행하는 프로세스로 이해하자.
동시에 여러 작업을 병렬로 처리한다.

UI 변경 + 네트워크 통신 + 다른 일

좀 더 쉽게 예를들면, 청소기를 돌리며 전화를 하며 라면 물을 올려두는 걸 동시에 진행한다고 생각하면 되겠다.

개념

Thread 1(Main Thread)에 Task가 여러개 있다고 가정하자.

서버 통신과 같은 Network 분산처리를 사용하고자 할 때, Main Thread는 Thread 2로 Task1(작업1)을 시작시킨다.

이 때, Main Thread는 Task1이 끝날 때까지 "기다리지 않는다"

이로인해 Main Thread가 다른 일처리를 시작할 수 있게된다.

비동기 처리 방식

크게 5가지가 있다

  1. Notification Center
  2. Delegate Pattern
  3. Closure
  4. RxSwift
  5. Combine (iOS 14~)

우선 이번에는 3번 Closure를 사용해서 네트워크 통신을 비동기로 진행하는 예제를 살펴보자.


지하철 도착 정보를 검색하는 앱이 있다.
여기서 UISearchBar에 해당 역이름을 검색하면 타이핑 한 값이 바뀔 때마다 실시간으로 비동기 네트워크 통신을 하여 TableView의 값을 갱신시켜보자.

  1. 우선 UIViewController에 UISearchBar의 Delegate를 self로 지정한다.
        let searchController = UISearchController()
        searchController.searchBar.delegate = self
        navigationItem.searchController = searchController
  1. UISearchBarDelegate protocol을 채택하여 타이핑 값이 바뀔 때마다 호출되는 textDidChange 함수를 작성하자.
extension StationSearchViewController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        requestStationName(from: searchText)
    }
}
  1. requestStationName: data request 함수 선언
    private func requestStationName(from stationName: String) {
    
        let urlString = "http://openapi.seoul.go.kr:8088/sample/json/SearchInfoBySubwayNameService/1/5/\(stationName)"
        
        //'서울'이라는 한글 키워드가 url에 들어있으므로 변환 시 특수문자로 변경되는 현상
        //addingPercentEncoding 사용
        AF.request(urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")
            .responseDecodable(of: StationResponseModel.self) { response in
                guard case .success(let data) = response.result else { return }
                print(data.stations)
            }
            .resume()
    }

여기서 Closure를 사용한 비동기 처리 부분은

 { response in
        guard case .success(let data) = response.result else { return }
        print(data.stations) //Check data response
 }

response 인자의 return 값을 살펴보면

success, Error 두 가지로 리턴하게 된다.
여기서는 따로 Error 처리 없이 Response 확인만 해보자.
guard 문으로 success
즉, 정상적으로 request와 서버로부터 response를 받은 상은 상태에서의 결과 값을 data에 넣어주고,
data를 정의한 Model(StationResponseModel)과 정합성을 확인한 뒤
값이 변경될 때마다 print 해주게 된다.


자 이제 직렬처리와 동시처리를 곁들여보자.

직렬처리(Serial)

선요약 : (보통 메인에서) 분산시킨 작업을 "다른 한 개의 Thread"에서 처리

예를 들어 Main Thread에서 여러개의 Task를 Thread 2에만 전달하여 Task를 생성시킬 때 직렬처리라고 한다.

동시처리(Concurrent)

선요약 : (보통 메인에서) 분산시킨 작업을 "다른 여러개의 Thread"에서 처리

인스타그램 피드를 예를들면, 각각의 Cell의 이미지를 서버로부터 불러와야 하는데

직렬처리처럼 한 개의 Thread에 Task를 집중시키면 버벅거리는 현상이 생긴다.

이 때 작업들은 각자 독립적이지만, 유사한 여러개의 작업을(image reading from server) 처리하기 때문에 작업을 여러개의 Thread로 분산시키는 동시처리를 사용한다.


동시처리로 여러개의 Thread로 일을 분산하면 되지, 왜 직렬처리를 할까?

단순하게 생각하면
동시처리의 경우 순서가 크게 상관이 없다.
반면 작업에 순서가 필요한 경우에는 직렬처리를 사용한다.


그럼 비동기랑 동시처리가 같은 말일까?

아니?

동기와 비동기는 작업을 보내는(보통 Main) Thread에서 대기열을 어떤 방식으로 처리할 지 결정하는 것!

직렬과 동시처리는 어떤 대기열을 사용할 지 결정하는 것!

전혀 다른 개념이므로 혼동하지 말자!

profile
Better than Yesterday

0개의 댓글