사전 태스크
용어함정

태스크

gabury1

태스크는 시스템이 처리하는 일 한 덩이를 가리키는 말입니다. 그 한 덩이가 무엇인지는 쓰는 자리마다 다릅니다. 어떤 자리에서는 실행되는 흐름 하나이고, 어떤 자리에서는 그 흐름들을 담는 그릇입니다. 같은 말을 주고받고도 서로 다른 층위를 떠올린 채 이야기가 흘러가기도 합니다.

상세

여러 맥락을 가로질러 남는 뼈대는 낱말 하나입니다. 어느 자리에서든 시작과 끝의 경계가 그어진 일감 한 덩이를 태스크라고 부릅니다. 그 이상은 뼈대가 정해 주지 않습니다.

갈리는 자리는 그 한 덩이가 무엇으로 존재하는가입니다. 어떤 자리에서는 그 자체로 실행되는 단위이고, 어떤 자리에서는 실행을 담는 자원의 그릇입니다. 어떤 자리에서는 코루틴을 감싼 비동기 객체이고, 어떤 자리에서는 큐에 쌓이는 구조체입니다. 어떤 자리에서는 사람이 갈래를 나눠 붙인 작업 한 덩이일 뿐입니다. Mach 커널 문서는 이 갈림을 직접 못박습니다. "a task has no life of its own—only threads execute instructions" 라고 적습니다. Mach의 태스크는 실행하는 쪽이 아니라 실행할 자원을 쥔 쪽입니다. 맥락 이름을 먼저 대야 뜻이 섭니다.

맥락별 뜻

맥락 뜻 출처
리눅스 커널 스케줄러가 다루는 실행 단위. 프로세스 안의 스레드마다 하나 proc(5) /proc/pid/task · 커널 CFS 설계 문서
Mach 커널 자원 소유의 단위. 주소 공간과 포트 권한과 스레드들을 담는 그릇 Kernel Programming Guide, Mach Overview
비동기 런타임 — Python 코루틴을 이벤트 루프에 얹어 돌리는 퓨처 비슷한 객체 Python 문서, Coroutines and Tasks
비동기 런타임 — .NET 값을 돌려주지 않고 대개 비동기로 실행되는 연산 하나를 나타내는 클래스 .NET 문서, System.Threading.Tasks.Task
HTML(HyperText Markup Language) 이벤트 루프 태스크 큐에 담기는 구조체. 필드는 실행할 단계와 소스와 문서 HTML Standard, Event loops
빌드 · 워크플로 빌드나 DAG(Directed Acyclic Graph, 방향 비순환 그래프)를 이루는 독립된 작업 한 덩이 Gradle User Manual · Airflow Tasks

리눅스 커널

proc(5)는 /proc/pid 아래마다 task 디렉터리를 두고, 그 아래에 task/tid 꼴의 디렉터리를 스레드마다 하나씩 둔다고 적습니다. tid는 그 스레드의 커널 스레드 식별자입니다. /proc/tid 디렉터리도 따로 있습니다. 그 내용은 대응하는 /proc/pid/task/tid 디렉터리와 같다고 문서가 적습니다. 스레드가 프로세스와 나란한 자리에 노출된다는 뜻입니다.

스케줄러 문서는 이 단위를 그대로 물려받습니다. CFS(Completely Fair Scheduler, 완전 공정 스케줄러)는 태스크마다 p->se.vruntime 값을 나노초 단위로 추적합니다. 태스크의 가상 실행 시간은 실제 실행 시간을 돌아가는 태스크 전체 수로 정규화한 값입니다. 고르는 규칙은 아주 단순하다고 문서가 적습니다. 언제나 p->se.vruntime이 가장 작은 태스크를 돌리려 합니다. 지금까지 가장 적게 실행된 태스크입니다. 태스크가 실행 가능 상태로 들어오면 enqueue_task가 그 스케줄링 개체를 레드블랙 트리에 넣고 nr_running을 하나 올립니다. 실행 가능 상태를 벗어나면 dequeue_task가 트리에서 빼냅니다.

Mach 커널

Mach는 단순하면서 강력하게 설계된 추상 몇 가지를 제공한다고 문서가 적습니다. 그중 태스크는 자원 소유의 단위이고, 스레드는 태스크 안의 실행 단위입니다. 스레드는 태스크 안의 제어 흐름 한 지점입니다. 태스크는 자기가 담은 스레드들에게 자원을 주려고 존재합니다. 문서는 이 쪼개기가 병렬성과 자원 공유를 위한 것이라고 적습니다.

태스크와 스레드는 값이 다릅니다. 문서는 태스크를 꽤 비싼 개체라고 적습니다. 태스크는 자원의 모음으로 존재합니다. 한 태스크 안의 스레드들은 모든 것을 나눠 씁니다. 서로 다른 두 태스크는 명시적인 행위 없이는 아무것도 나눠 쓰지 않습니다. 스레드는 태스크에 비해 꽤 가벼운 개체입니다. 만드는 값이 꽤 싸고 굴리는 부담도 작습니다. 스레드는 자기 가상 주소 공간을 정하는 단 하나의 태스크에 속합니다.

리눅스와 Mach는 같은 말을 서로 다른 칸에 걸어 두었습니다. 리눅스에서 태스크라고 부르는 자리에 Mach는 스레드를 놓았습니다. Mach에서 태스크라고 부르는 자리에 리눅스는 프로세스를 놓았습니다. 두 문서를 섞어 읽으면 층위가 한 칸씩 밀립니다.

flowchart TD
    subgraph 리눅스
        P["프로세스"] --> A["태스크 · 스레드 하나"]
        P --> B["태스크 · 스레드 하나"]
    end
    subgraph Mach
        M["태스크 · 자원을 담는 그릇"] --> C["스레드"]
        M --> D["스레드"]
    end

비동기 런타임

Python 문서는 asyncio.Task를 파이썬 코루틴을 돌리는 퓨처 비슷한 객체라고 적습니다. 그러면서 스레드 안전하지 않다고 곧바로 덧붙입니다. 태스크는 이벤트 루프에서 코루틴을 돌리는 데 쓰입니다. 코루틴이 어떤 퓨처를 기다리면 태스크가 그 코루틴의 실행을 멈춰 둡니다. 그리고 퓨처가 끝나면 감싸고 있던 코루틴의 실행을 다시 이어 갑니다.

sequenceDiagram
    participant 이벤트루프
    participant 태스크
    participant 코루틴
    이벤트루프->>태스크: 실행을 맡김
    태스크->>코루틴: 실행을 이어 감
    코루틴->>태스크: 퓨처를 기다림
    Note over 태스크: 코루틴 실행을 멈춰 둔다
    태스크->>코루틴: 퓨처가 끝나면 다시 이어 감

asyncio.create_task()로 감싸면 그 코루틴은 곧 실행되도록 자동으로 예약됩니다. 문서가 든 예에서 돌려받은 task 값은 두 가지로 쓰입니다. 감싼 코루틴을 취소하는 데 쓰거나, 그냥 await 해서 끝날 때까지 기다리는 데 씁니다.

.NET 문서는 Task가 비동기 연산 하나를 나타낸다고 적습니다. Task 클래스는 값을 돌려주지 않고 대개 비동기로 실행되는 연산 하나를 나타냅니다. 문서는 Task 객체가 .NET Framework 4에서 처음 나온 태스크 기반 비동기 패턴의 중심 구성 요소 가운데 하나라고 적습니다. 파이썬과 다른 언어인데 이 자리에서만은 뜻이 겹칩니다.

HTML 이벤트 루프

HTML 명세는 태스크를 구조체로 정의합니다. 필드가 넷입니다. 그 태스크가 할 일을 적은 단계들, 관련된 태스크들을 묶고 차례를 정하는 데 쓰는 소스, 딸린 문서, 그리고 태스크가 도는 동안 스크립트 평가를 추적하는 환경 설정 객체 집합입니다. 창 이벤트 루프에 속하지 않는 태스크라면 문서 필드는 널입니다. 태스크는 자기 문서가 널이거나 완전히 활성이면 실행 가능합니다.

flowchart TD
    S["태스크 소스"] --> Q["태스크 큐"] --> L["이벤트 루프"]

명세는 태스크마다 소스 필드에 따라 특정 태스크 소스에서 온 것으로 정의된다고 적습니다. 이벤트 루프마다 모든 태스크 소스는 특정 태스크 큐 하나에 연결되어야 합니다. 태스크 소스는 표준 안에서 논리적으로 다른 종류의 태스크들을 갈라 놓는 데 쓰입니다. 사용자 에이전트가 그것들을 구별하고 싶어 할 수 있기 때문입니다. 태스크 큐는 사용자 에이전트가 한 이벤트 루프 안의 태스크 소스들을 한데 모으는 데 쓰입니다.

빌드와 워크플로

Gradle 사용자 문서는 태스크를 빌드가 수행하는 독립된 작업 한 덩이라고 적습니다. 클래스를 컴파일하는 일, jar 를 만드는 일, 자바독을 생성하는 일, 아카이브를 저장소에 배포하는 일이 문서가 든 예입니다.

Airflow 문서는 태스크를 Airflow에서의 실행 기본 단위라고 적습니다. 태스크들은 DAG로 배열됩니다. 그리고 태스크 사이에 업스트림과 다운스트림 의존성이 걸립니다. 돌아야 할 차례를 그렇게 표현합니다. 문서는 태스크의 기본 갈래를 셋으로 적고 그중 오퍼레이터를 미리 정의된 태스크 틀이라고 소개합니다.

이 두 자리에서 태스크는 실행 흐름도 자원 그릇도 아닙니다. 빌드나 DAG를 이루는 독립된 작업 한 덩이입니다.

경계

셸의 잡

셸에서 &로 뒤로 돌린 파이프라인 한 벌도 태스크인가. 아닙니다. 그건 잡입니다.

POSIX(Portable Operating System Interface) 기본 정의는 잡을 프로세스들의 집합이라고 적습니다. 셸 파이프라인 하나와 거기서 갈라져 나온 모든 프로세스를 묶은 것이고, 그것들이 전부 같은 프로세스 그룹에 있습니다. 태스크라는 말은 이 정의에 나오지 않습니다. 세는 단위가 프로세스 그룹이라는 점에서 리눅스 커널의 태스크와도 다릅니다.

관련 항목

리눅스 커널에서 이것과 나란히 식별되는 단위

스레드 · 프로세스 · 스레드 ID · 프로세스 ID

리눅스 스케줄러가 이것을 고르고 재는 방식

스케줄러 · 완전 공정 스케줄러 · 가상 실행 시간 · 정규화 · 스케줄링 · 레드블랙 트리 · 실행 가능 상태

Mach 커널에서 이것이 소유·공유하는 자원과 실행 단위

가상 주소 공간 · 포트 권한 · 이름 공간 · 자원 공유 · 병렬성 · 스레드 · 제어 흐름

비동기 런타임에서 이것을 이루는 구성 요소

코루틴 · 이벤트 루프 · 퓨처 · 취소 · 비동기 연산 · 태스크 기반 비동기 패턴

비동기 런타임에서 이것을 실제로 구현한 제품

asyncio · .NET

브라우저 이벤트 루프에서 이것을 정의하는 표준과 구성 요소

HTML · 태스크 소스 · 태스크 큐 · 사용자 에이전트 · 환경 설정 객체

빌드와 워크플로에서 이것이 놓이는 흐름과 산출물

DAG · 오퍼레이터 · 업스트림 의존성 · 아카이브 · 배포

빌드와 워크플로에서 이것을 실제로 구현한 제품

Gradle · Airflow

셸에서 이것과 헷갈리는 이웃

잡 · 프로세스 그룹 · 셸 파이프라인 · 작업 제어 · 셸 · 파이프라인 · POSIX

다른 이름: task