개발을 하다보면 “한 번에 끝나지 않는 작업”을 다뤄야 하는 경우가 많다.
Unity에서는 서버 응답을 기다리거나, 리소스를 로딩하거나, 일정 시간 뒤에 연출을 이어가는 작업이 모두 여기에 포함된다.
이런 작업을 동기 방식으로 처리하면 메인 스레드가 멈춰 프레임 드랍이 발생할 수 있다. 반대로 비동기 방식으로 설계하면 프레임을 유지하면서 작업을 이어갈 수 있다.
이번 글에서는 동기/비동기 프로그래밍에 대해 알아보고,
Unity에서 자주 사용하는 async/await(Task)도 간단히 살펴볼 예정이다.
----------------------------------------------------------------------------------------------------------------------------------------------------------------
1) 동기(Synchronous)란?
동기는 작업을 호출한 흐름(스레드)이 결과를 받을 때까지 기다리는 방식
호출 → 작업 수행 → 결과 반환
즉, 앞 작업이 끝나야 다음 작업이 진행된다.
간단 예시 코드
// (개념 예시) 오래 걸리는 작업이 끝날 때까지 다음 줄로 못 넘어감
void LoadSomethingSync()
{
DoHeavyWork(); // 여기서 오래 걸리면 이 함수가 끝날 때까지 멈춤
Debug.Log("Done");
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------
2) 비동기(Asynchronous)란?
비동기는 작업을 시작(요청)해두고, 완료되면 나중에 결과를 받는 방식
호출 → (즉시 반환) → 나중에 완료 통지(콜백/이벤트/await) → 결과 처리
대기 시간 동안 다른 일을 처리할 수 있다.
핵심은 동시에 처리하는게 아닌,
요청(시작)과 완료(결과 처리)가 분리되어 흐름을 막지 않는다는 점이다.
----------------------------------------------------------------------------------------------------------------------------------------------------------------
3) 자주 하는 오해(비동기 = 멀티스레드?)
비동기는 멀티스레드로 구현될 수도 있지만 반드시 그렇진 않다.
비동기 I/O는 OS가 처리하고 완료 시점에 통지를 받는 방식이 많고
Unity 코루틴도 비동기처럼 보이지만 기본적으로는 메인 스레드에서 프레임 단위로 나눠 실행된다.
----------------------------------------------------------------------------------------------------------------------------------------------------------------
4) async/await이란?
async/await는 비동기 작업의 완료를 콜백 없이도 ‘동기 코드'처럼 읽히게 만드는 문법이다.
async: 이 메서드는 비동기 흐름을 가지며 await를 사용할 수 있음
await: 비동기 작업이 완료될 때까지 기다렸다가, 완료되면 다음 줄 실행
----------------------------------------------------------------------------------------------------------------------------------------------------------------
5) Task란?
Task는 나중에 완료될 작업(그리고 예외/결과)을 표현하는 반환 타입이다.
즉, async가 “비동기 흐름의 선언”이라면,
Task는 그 비동기 흐름을 반환하고 추적 가능하게 만드는 표준 단위라고 할 수 있다.
+++
Task가 하는 역할
완료 상태 표현: 끝났는지/진행 중인지/실패했는지
예외 전달: 비동기 중 발생한 예외를 담고, await 시점에 다시 던져짐
작업 조합(합성): Task.WhenAll, Task.WhenAny로 여러 비동기를 묶어 처리
결과 전달(Task): 결과가 있는 비동기는 Task<T>로 반환
async + Task / Task<T> / void 차이
async Task : 반환값 없음, 완료/예외 추적 가능
async Task<T> : 반환값 있음
async void : 호출자가 기다릴 수 없고 예외 처리도 어려움 → 이벤트 핸들러 등 특수한 경우만

----------------------------------------------------------------------------------------------------------------------------------------------------------------
6) async/await 간단한 예시 코드
(1)Task로 “대기” 표현
using System.Threading.Tasks;
using UnityEngine;
public class AsyncAwaitDelayExample : MonoBehaviour
{
private async void Start()
{
Debug.Log("Start");
await Task.Delay(2000);
Debug.Log("After 2 seconds");
}
}
(2)UnityWebRequest를 await 스타일로 감싸기
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
public class AsyncWebRequestExample : MonoBehaviour
{
private async void Start()
{
string url = "https://example.com";
string text = await GetTextAsync(url);
Debug.Log($"Response length: {text?.Length}");
}
private async Task<string> GetTextAsync(string url)
{
using (var req = UnityWebRequest.Get(url))
{
var op = req.SendWebRequest();
while (!op.isDone)
await Task.Yield();
if (req.result != UnityWebRequest.Result.Success)
{
Debug.LogError(req.error);
return null;
}
return req.downloadHandler.text;
}
}
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------
7) 오늘의 한 줄 요약
동기는 요청한 작업의 결과를 ‘기다리는 방식’,
비동기는 요청과 결과 처리를 분리해 ‘기다리는 동안 다른 일을 할 수 있게 하는 방식’이다.
'1일 1 cs' 카테고리의 다른 글
| 7. 대리자(delegate)와 event란? (0) | 2026.01.22 |
|---|---|
| 6. Unity의 생명주기(Life Cycle)란? (0) | 2026.01.21 |
| 4. 제네릭 이란? (+ 오브젝트 풀링) (0) | 2026.01.18 |
| 3. 디자인 패턴(싱글톤, 팩토리, 상태, 전략)이란? (0) | 2026.01.17 |
| 2. 설계 원칙(SOLID)이란? (0) | 2026.01.16 |
