서로 독립적인 표현식을 함께 실행하고 하나의 이름 붙은 결과 레코드가
필요할 때 concurrent를 사용합니다. 일반 애플리케이션 코드는 명시적인
대체 값을 갖춘 제한형 형식을 선택하는 것이 좋습니다.
제한 시간 안에 완료하기
다음 코드를 concurrency-success.tpz로 저장합니다.
let result = concurrent(timeout: 3s) {
total: 1 + 2
label: "ready"
} else {
{ total: -1, label: "timeout" }
}
print("{result.total} {result.label}")검사한 뒤 실행합니다.
topaz check concurrency-success.tpz
topaz run concurrency-success.tpz
두 작업이 제한 시간 안에 끝나므로 각 이름이 결과 레코드의 필드가 됩니다.
3 ready레코드는 작업 이름과 값을 연결합니다. 어느 작업이 먼저 시작하거나 끝났는지는 이 결과에서 알 수 없습니다.
시간 초과 시 대체 값 선택하기
두 번째 프로그램에는 끝나지 않는 작업이 있습니다. 다음 코드를
concurrency-timeout.tpz로 저장합니다.
function spin() -> int {
let mut i = 0
while true { i += 1 }
i
}
let result = concurrent(timeout: 5ms) {
stuck: spin()
} else {
{ stuck: -1 }
}
print("{result.stuck}")검사한 뒤 실행합니다.
topaz check concurrency-timeout.tpz
topaz run concurrency-timeout.tpz
제한 시간이 먼저 끝나면 일부 작업의 결과는 공개되지 않고, else가
전체 결과를 제공합니다.
-1세 가지 결과 구분하기
| 제한 시간 전에 일어난 일 | 표현식의 결과 |
|---|---|
| 모든 작업이 완료됨 | 작업마다 하나의 필드를 가진 레코드 |
| 제한 시간이 먼저 끝남 | else 블록의 값 |
| 한 작업에서 실행 오류가 발생함 | 전체 표현식이 실행 오류로 끝나며 else는 실행되지 않음 |
작업이 Err(error)를 계산했다면 실행 오류가 아닙니다. 그 Result는
이름 붙은 레코드 필드에 저장되는 일반 값입니다. 대체 값은 성공한 작업
레코드와 타입이 호환되어야 하므로, 두 예제의 성공 경로와 else 경로는
같은 필드 이름과 호환되는 값 타입을 사용합니다.
이름이 보장하지 않는 것
작업 이름은 결과와의 연결만 고정할 뿐 실행 순서는 고정하지 않습니다.
토파즈는 작업 시작 순서, 완료 순서, 출력이 섞이는 순서, 공정성,
결정적인 실행 순서를 보장하지 않습니다. 순서가 중요하다면 작업 안에서
print하지 말고, 예제처럼 합류한 뒤 레코드를 출력하세요.
시간 초과 뒤 남겨진 작업의 취소와 정리는 런타임 정책입니다. 버려진 작업에서 나중에 발생한 실행 오류는 토파즈 표현식이 관찰하지 않습니다. 따라서 특정 스케줄러나 시간 초과 뒤의 이식 가능한 정리를 전제로 삼으면 안 됩니다.
흔한 수정
3s나5ms처럼 숫자와 단위를 붙여 씁니다..seconds같은 속성 형식은 시간 리터럴이 아닙니다.- 제한 시간을 쓰면
else가 반드시 필요하고, 단순 합류에는else를 붙일 수 없습니다. else는 시간 초과만 처리합니다. 실행 오류를 잡거나Err를 풀지 않습니다.- 작업 이름은 중복될 수 없으며, 일부 결과를 꺼내는 문법은 없습니다.
제한 시간 없는 concurrent { ... } 합류는 기다림 자체가 설명의
핵심인 고급 동시성 문서에서 사용할 수 있습니다. 일반 예제의 기본
형식은 아닙니다.
암묵적인 비동기 모델, async/await 문법, 공개 작업 핸들, 일반 시간
연산, 명시된 취소 프로토콜은 없습니다. 관찰 가능한 실행 오류와 순서의
경계는 실행 환경 동작에서, 익숙해 보이지만
지원하지 않는 형식은 금지·유예 형식에서
확인하세요.