프로그래밍 언어/C#
비동기 프로그래밍
가든_
2023. 12. 25. 22:01
🗓️ 주제
- .Net에서 비동기 처리에 대해 (Task) 학습(2023/11/16, 2023/11/22)
- 비동기 프로그래밍의 이점과 UniTask의 필요성(2023/11/20)
🎦 비동기 프로그램
동기와 비동기
- 동기 : 수행 주체(스레드)가 하나인 실행
- 스레드가 하나이면 모든 코드를 혼자 실행하며 다음 단계의 실행은 현재 코드의 수행이 끝나야만 실행 가능
- 작업이 완료되기를 기다리는 방식
- 현재 줄의 코드가 완료되어야만 다음 코드를 실행
- 비동기 : 수행 주체(스레드)가 다수인 실행
- 스레드가 서로의 코드를 기다리지 않고 개별적으로 작업 수행
- 메인 스레드에서 별도의 스레드를 생성하여 해당 스레드가 개별 작업을 맡고 작업이 완료되면 결과를 메인 스레드로 전달하는 형식
비동기 프로그래밍의 장점
- 성능 병목 현상을 방지하고, 애플리케이션의 전체적인 응답성을 향상시킬수 있다.
- 반응성 향상
- 액세스 속도가 느리고 지연되는 작업을 할 때(ex. 웹 리소스 다운) 동기 프로그래밍에서는 해당 작업 동안 전체 애플리케이션이 중지되지만, 비동기 프로그래밍에서는 중지되지 않고, 다른 작업을 계속 수행할 수 있다.
- 지원 메서드
웹 액세스 https://learn.microsoft.com/ko-kr/dotnet/api/system.net.http.httpclient 파일 작업 JsonSerializer StreamReader StreamWriter XmlReader XmlWriter WCF 프로그래밍 https://learn.microsoft.com/ko-kr/dotnet/framework/wcf/synchronous-and-asynchronous-operations - 동기 프로그램은 한 개의 스레드를 사용하기 때문에 하나의 프로세스가 차단되면 모든 프로세스가 차단됨. 그렇기 때문에 응답이 중지되면 더 기다리지 않고 애플리케이션이 실패했다고 결론 내림. 반대로 비동기 프로그램은 다수의 스레드가 존재하기 때문에 UI에 계속 응답할 수 있음. 그렇기 때문에 다른 작업을 하고 있음에도 창의 크기를 바꾸거나 종료를 할 수 있음
- 액세스 속도가 느리고 지연되는 작업을 할 때(ex. 웹 리소스 다운) 동기 프로그래밍에서는 해당 작업 동안 전체 애플리케이션이 중지되지만, 비동기 프로그래밍에서는 중지되지 않고, 다른 작업을 계속 수행할 수 있다.
- 작성이 간편
- C#의 async/await 키워드를 사용하면 쉽게 비동기 메서드를 만들 수 있음
- 비동기 메서드 : async 키워드를 사용해서 정의한 비동기 메서드
public **async** Task GetUrlContentLengthAsync() { var client = new HttpClient(); Task getStringTask = client.GetStringAsync("<https://learn.microsoft.com/dotnet>"); DoIndependentWork(); string contents = **await** getStringTask; return contents.Length; } void DoIndependentWork() { Console.WriteLine("Working..."); } - C#의 async/await 키워드를 사용하면 쉽게 비동기 메서드를 만들 수 있음
비동기 프로그래밍의 단점
- 비동기 애플리케이션을 쓰는 방법이 복잡해서 사용과 디버깅, 유지 관리가 어려울 수 있다.
- 다수의 스레드들이 특정 자원을 공유할 때 자원의 상태 변화나 접근 순서에 따라 문제가 발생하게 됨 → 스레드 동기화 기법을 통해 해결할 수 있다.
🖥️ 프로세스(Process)
- 프로그램을 실행하는 과정
📀 스레드(thread)
- 프로세스를 구성하는 작업 단위
- 싱글 스레드 환경 : 프로세스를 구성하는 스레드가 하나
- 멀티 스레드 환경 : 프로세스를 구성하는 스레드가 여러개
멀티스레딩
장점
- 성능 향상
- 2개 이상의 물리코어를 가진 컴퓨터가 하나의 프로세스를 여러 스레드에게 작업을 나누어 할당한다면 작업이 빨라짐
- 물리코어 : 컴퓨터에서 프로그래밍을 실행하는 일을 하는 일꾼
- 유니티의 멀티스레딩은 물리코어 1당 하나의 스레드를 만든다.
단점
- 경쟁 조건(Race Condition)
- 독립된 두 작업이 동시에 같은 값을 사용하려고 할 때 그들 사이의 경쟁에 의해서 실행 결과를 예측할 수 없게 되는 것.
- ex) A스레드와 B스레드가 동시에 작동하고 있고, a라는 숫자에 각각 곱하기, 나누기를 하고 있다면 결과를 예측할 수 없다.
👉멀티 스레딩 환경에서는 각 스레드들이 병렬(여러 명의 일꾼이 동시에 각자의 일을 처리함)로 일들이 수행되기 때문에 경쟁 조건이 발생할 가능성이 있다.
- 데드락
- 서로 아무것도 못하고 대기하는 상황이 지속될 때

- 서로 아무것도 못하고 대기하는 상황이 지속될 때
👉멀티 스레딩 환경에서 스레드들의 할 일을 잘못 정하면 각 스레드들의 일이 꼬여서 아무일도 하지 못하는 데드락 상태가 발생할 수 있다.
- 종속성 문제
- 스레드들의 작업이 종속성을 가지지 않아서 병렬로 처리하기 때문에 어떤 단계가 먼저 끝날지 예측할 수 없을때 생기는 문제
👉 멀티 스레딩 환경에서는 각 일들이 동시에 실행되고, 서로의 일이 연관이 있는지 스레드들은 모르기 때문에 종속성 문제가 발생할 수 있다.
동작 방법
- 스레드가 동작할 스택 할당
- 유저 모드 : 1MB, 커널 모드 : 12KB
- 스레드 생성
- 현재 프로세스에서 로딩된 모든 DLL에 스레드 생성을 통보
- 스레드 삭제
- 사용한 메모리와 자원 반환
- 현재 프로세스의 모든 DLL에 스레드 삭제를 통보
🚫 멀티 스레드의 문제점
작업 부하가 크다(스레드 사용에 따른 오버헤드)
🚫 스레드 생성시 주의 사항
오버헤드가 발생할 수 있다. 스레드의 생성/삭제 마다 메모리 할당과 전체 DLL에 스레드 생성/삭제를 통보하기 때문.
작업 스케쥴링
- 어떤 스레드가 CPU 자원을 얼마나 사용할지 CPU가 결정한다.
- 스케쥴링은 20ms 단위로 반복해서 수행된다.
- 1 CPU가 여러개의 스레드에 대한 스케쥴링을 하게되면 큰 부담이 된다.
- 하지만 여러개의 CPU를 탑재한 컴퓨터에서는 CPU의 활용을 높히는 좋은 수단이다.
- 스레드 사용은 CPU의 분산처리를 가능하게 해서 CPU 성능을 끌어올린다.
- 스레드가 스케쥴링 되어서 다음 스레드로 변경되면 컨텍스트 스위칭이 발생한다.
컨텍스트 스위칭(Context Switching)
- 데이터 전환
- CPU는 작업을 위해 필요한 데이터를 레지스터와 가상 공간에 저장한다.
- 작업이 전환되면 레지스터의 내용과 참조하던 가상 공간을 전환한다.
🌀 스레드 풀(Thread Pool)
- .NET에서 스레드 사용의 부담과 불편을 줄이기 위해 제공
- System.Threading.ThreadPool
- 스레드들이 담겨있는 수영장이라고 생각하면 됨
- 작업이 끝났을때 스레드가 파괴되지 않고 스레드 풀로 복귀해 다음 작업을 대기한다
동작 방법
- 스레드 풀의 Queue에 작업이 Enqueue
- 델리게이트 형태로 Enqueue 됨
- Queue에 작업이 쌓이면 스레드 풀에서 대기중인 스레드가 Deque하고 작업 수행
- 대기중인 스레드가 없다면 스레드 생성
- 기본적으로 스레드 풀은 하나의 스레드를 가지고 있으며 기다리는 작업이 Queue에 쌓일 경우 추가 스레드를 생성해 Queue 내부의 작업을 해치운다.
- 작업이 완료된 스레드는 스레드 풀로 복귀
- 모든 작업이 완료된다면 일정 시간(기본 2분)동안 대기한 후 스레드 풀의 스레드들이 스스로 파괴된다.
- 불필요한 자원 점유 해제
장점
- 스레드를 재사용해서 스레스의 생성/파괴에서 오는 오버헤드 줄임
- 스레드 생성시 CPU별로 스레드가 할당되어 멀티CPU에 대한 스레드 할당이 자체적으로 최적화된 로직으로 수행된다.
QueueUserWorkItem()
- 스레드 풀에 작업 Enqueue
- QueueUserWorkItem(WaitCallback callBack);
- QueueUserWorkItem(WaitCallback callBack, object state);
- WaitCallback 델리게이트로 작업 전달
- object state로 델리게이트에서 사용될 파라미터 전달
📜참고자료
Unitask cancellation. What is the difference between Task and Coroutine?