코드를 동기적으로 작동시키는 것과 비동기적으로 작동시키는 것은 리소스 최적화와 관련해서 매우 중요하다.
특별한 지시가 없다면 C#은 코드를 동기적으로 작동시키며
동기적이라는 것은 명령문을 순차적으로, 즉 하나의 작업이 완료되지 않았다면 다음 작업을 실행하지 않는다.
동기 (Synchronous)
동기적으로 코드를 실행하는것은 다음 키워드들로 설명할 수 있다.
- 단일 흐름: 작업이 완료될 때까지 현재 쓰레드가 다른 일을 하지 못하고 기다려야 한다.
- 차단(Blocking): 작업이 완료될 때까지 호출한 쓰레드*가 차단된다.
- 단순성: 구현이 상대적으로 단순하며, 코드의 흐름이 직관적이고 읽기 쉽습니다.
쓰레드*란? : 프로세스 내에서 실행되는 작은 실행 단위이다. 쓰레드가 차단된다는 것은 어떤 작업이 완료될 때까지 해당 작업을 호출한 스레드가 멈추고 다른 작업을 수행하지 못하는 상황이다.
동기적 코드 사용 사례
- 간단한 작업: 작업이 매우 짧고 즉시 완료될 수 있는 경우.
- 순차적 처리: 작업의 순서가 중요하며, 이전 작업이 완료된 후에 다음 작업이 실행되어야 하는 경우.
- UI 업데이트: UI 업데이트와 같이 즉각적인 처리가 필요한 경우 (UI 스레드에서 실행되는 경우).
동기적으로 구현한 코드 예시
using System;
class Program
{
static void Main(string[] args)
{
// 작업 1
FirstJob();
// 작업 2
SecondJob();
}
static void FirstJob()
{
Console.WriteLine("작업 1 실행 중");
System.Threading.Thread.Sleep(2000); // 2초 대기
Console.WriteLine("작업 1 실행 완료");
}
static void SecondJob()
{
Console.WriteLine("작업 2 실행 중");
System.Threading.Thread.Sleep(2000); // 2초 대기
Console.WriteLine("작업 2 실행 완료");
}
}
특별한 명령문 없이 순서대로 함수를 호출했고 예상대로 각각의 순서대로 2초 간격을 두고 구현된다.
비동기 (Asynchronous)
비동기적으로 코드를 실행하는것은 해당 작업이 완료되는 것을 기다리지 않고 다른 작업을 수행하는 방식이다.
비동기의 키워드는 다음과 같다.
- 병렬 흐름: 작업이 비동기로 수행되며, 완료될 때까지 다른 작업을 수행할 수 있다.
- 비차단(Non-blocking): 작업이 완료될 때까지 호출한 쓰레드가 차단되지 않는다.
- 복잡성: 구현이 동기 방식보다 복잡할 수 있으며, 코드의 흐름이 비직관적일 수 있다.
- async: 비동기적 메소드를 구현할때는 async 키워드를 사용해서 구현해야 한다.
- async: async 메서드는 반드시 Task 또는 Task<T>를 반환해야 한다.
- await: 비동기 작업을 기다릴 때 사용된다.
- await: await는 Task 또는 Task<T>의 완료를 비동기적으로 기다리며, 이 동안 호출한 스레드를 차단하지 않습니다
비동기적 코드 사용 사례
- I/O 바운드 작업: 파일 읽기/쓰기, 네트워크 요청, 데이터베이스 쿼리와 같은 작업.
- 시간이 오래 걸리는 작업: 긴 시간 동안 실행되는 계산, 외부 서비스 호출 등.
- 병렬 처리: 여러 작업을 동시에 실행하여 응답성을 높이고자 할 때.
- UI 응답성 유지: 비동기 작업을 통해 UI 스레드가 차단되지 않도록 하는 경우.
비동기적으로 구현한 코드 예시
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("동기 작업 1 시작");
SynchronousTask1();
Console.WriteLine("동기 작업 1 완료");
Console.WriteLine("비동기 작업 시작");
await PerformAsyncTask();
Console.WriteLine("동기 작업 2 시작");
SynchronousTask2();
Console.WriteLine("동기 작업 2 완료");
}
static void SynchronousTask1()
{
// 동기적으로 수행할 작업 1
Console.WriteLine("동기 작업 1 수행 중...");
System.Threading.Thread.Sleep(1000); // 1초 대기
}
static void SynchronousTask2()
{
// 동기적으로 수행할 작업 2
Console.WriteLine("동기 작업 2 수행 중...");
System.Threading.Thread.Sleep(1000); // 1초 대기
}
static async Task PerformAsyncTask()
{
// 비동기적으로 수행할 작업
Console.WriteLine("비동기 작업 수행 중...");
await Task.Delay(1000); // 1초 대기
Console.WriteLine("비동기 작업 완료");
}
}
동기와 비동기적 함수를 섞은 예제이다. 순서대로 살펴보자.
1. 동기 작업 1이 수행된다.
2. 비동기 작업이 수행된다. 이때 await 키워드를 사용해 비동기 작업이 완료될 때 까지 대기시킨다.
3. 비동기 작업 완료 후 동기 작업 2를 수행한다.
순서대로 잘 실행되는 모습이다.
위 코드의 순서를 그대로 유지한 상태에서 비동기 작업이 완료될 때 까지 기다리지 않고 코드를 실행 해 보자.
static async Task Main(string[] args)
{
Console.WriteLine("동기 작업 1 시작");
SynchronousTask1();
Console.WriteLine("동기 작업 1 완료");
Console.WriteLine("비동기 작업 시작");
// 비동기 시작
Task asyncTask = PerformAsyncTask();
Console.WriteLine("동기 작업 2 시작");
SynchronousTask2();
Console.WriteLine("동기 작업 2 완료");
}
await 키워드로 비동기 함수를 기다리지 않고 실행시킨 결과가 이렇게 나온다.
핵심 키워드 정리
- 스레드: 프로세스 내에서 실행되는 작은 실행 단위. 여러 스레드를 통해 병렬 처리가 가능함.
- 차단(Blocking): 특정 작업이 완료될 때까지 호출한 스레드가 멈추고 다른 작업을 수행하지 못하는 상태.
- 동기적 코드: 순차적으로 코드를 실행하고 스레드 차단을 유발하며, 스레드가 작업이 완료될 때까지 대기함.
- 비동기적 코드: 순차적으로 코드를 기다리지 않고 스레드를 차단하지 않으며 작업이 완료될 때까지 비동기적으로 대기함.
'C#' 카테고리의 다른 글
C# - 라이브러리 vs 프레임워크 (2) | 2024.07.11 |
---|---|
C# - Struct 와 Class의 차이점 (0) | 2024.06.21 |
C# - 스레드(Thread) (1) | 2024.06.18 |
C# - System / Collections / Generic Collection (0) | 2024.06.11 |
C# - 가비지 컬렉션(Garbage Collection) (0) | 2024.06.07 |