그린 스레드

컴퓨터 프로그래밍에서 **그린 스레드**(Green thread)는 기반이 되는 운영체제 (OS)에 의해 기본적으로 스케줄링되지 않고, 런타임 라이브러리 또는 가상 머신 (VM)에 의해 스케줄링되는 스레드이다. 그린 스레드는 네이티브 OS 기능에 의존하지 않고 다중 스레드 환경을 에뮬레이트하며, 커널 공간 대신 사용자 공간에서 관리되어 네이티브 스레드 지원이 없는 환경에서도 작동할 수 있다.

## 어원
그린 스레드는 자바 프로그래밍 언어의 원래 스레드 라이브러리 이름(버전 1.1에 출시되었고 버전 1.3에서는 네이티브 스레드로 전환되면서 폐기됨)에서 유래했다. 이 라이브러리는 썬 마이크로시스템즈의 그린 팀(The Green Team)에서 설계했다.

## 역사
그린 스레드는 1997년부터 2000년 사이에 자바에서 잠시 사용되었다.

그린 스레드는 협력적 동시성을 통해 단일 운영체제 스레드를 공유하므로, 운영체제 스레드처럼 병렬 처리 성능 향상을 달성할 수 없다. 코루틴과 그린 스레드의 주요 이점은 구현의 용이성이다.

## 성능

멀티 코어 프로세서에서는 네이티브 스레드 구현이 여러 프로세서에 작업을 자동으로 할당할 수 있는 반면, 그린 스레드 구현은 일반적으로 그렇지 못하다. 일부 VM에서는 그린 스레드를 훨씬 빠르게 시작할 수 있다. 그러나 단일 프로세서 컴퓨터에서는 가장 효율적인 모델이 아직 명확하게 결정되지 않았다.

리눅스 커널 버전 2.2(1999년 출시)를 실행하는 컴퓨터에서의 벤치마크는 다음을 보여주었다.
* 그린 스레드는 스레드 활성화 및 동기화에서 리눅스 네이티브 스레드보다 훨씬 뛰어난 성능을 보인다.
* 리눅스 네이티브 스레드는 I/O 및 문맥 교환 작업에서 약간 더 나은 성능을 보인다.

그린 스레드가 블로킹 시스템 호출을 실행하면 해당 스레드뿐만 아니라 프로세스 내의 모든 스레드가 블록된다. 이 문제를 피하려면 그린 스레드는 논블로킹 입출력 또는 비동기 입출력 작업을 사용해야 한다. 비록 사용자 측의 복잡성이 증가할 수 있지만, 그린 스레드를 구현하는 가상 머신이 각 I/O 작업에 대해 특정 I/O 프로세스(사용자에게 숨겨진)를 생성한다면 복잡성이 줄어들 수 있다.

네이티브 스레드 사용을 허용하고 스레드 활성화 및 동기화 오버헤드를 줄이는 메커니즘도 있다.
* 스레드 풀은 제한된 수의 스레드를 재사용하여 새 스레드 생성 비용을 줄인다.
* 가상 머신과 네이티브 스레드를 사용하는 언어는 필요 없을 때 코드 블록 동기화를 피하기 위해 탈출 분석을 사용할 수 있다.

## 자바 가상 머신의 그린 스레드

자바 1.1에서는 그린 스레드가 자바 가상 머신 (JVM)에서 사용되는 유일한 스레딩 모델이었다. 적어도 솔라리스에서는 그랬다. 그린 스레드는 네이티브 스레드에 비해 몇 가지 제한 사항이 있어, 이후 자바 버전에서는 네이티브 스레드 선호로 변경되었다.

예외는 저전력 장치용 운영체제와 자바 가상 머신의 혼합 형태인 Squawk 가상 머신이다. 이 가상 머신은 네이티브 코드 사용을 최소화하고 격리된 환경을 지원하기 위해 그린 스레드를 사용한다.

Kilim과 Quasar는 자바 컴파일러가 생성하는 자바 바이트코드를 수정하여 JVM의 최신 버전에서 그린 스레드를 구현하는 오픈 소스 프로젝트이다(Quasar는 코틀린과 클로저도 지원한다).

## 다른 언어의 그린 스레드
네이티브 스레드 대신 그린 스레드와 동등한 것을 구현하는 다른 프로그래밍 언어들도 있다. 예시:
* 치킨 스킴은 일급 연속체를 기반으로 하는 경량 사용자 수준 스레드를 사용한다.
* 커먼 리스프
* C파이썬은 버전 3.4부터 기본적으로 asyncio를 지원하며, greenlet, eventlet 및 gevent와 같은 대체 구현이 존재한다. PyPy
* 크리스탈은 파이버를 제공한다.
* D는 비동기 입출력에 사용되는 파이버를 제공한다.
* Dyalog APL은 이를 스레드라고 부른다.
* 얼랭
* Go는 고루틴이라고 불리는 것을 구현한다.
* 하스켈
* 줄리아는 Task에 그린 스레드를 사용한다.
* 림보
* 루아는 동시성을 위해 코루틴을 사용한다. 루아 5.2는 lua_yieldk, lua_callk, lua_pcallk 함수를 통해 진정한 C 코루틴 의미론을 제공한다. CoCo 확장은 루아 5.1에서 진정한 C 코루틴 의미론을 허용한다.
* 님은 비동기 I/O 및 코루틴을 제공한다.
* OCaml은 버전 5.0부터 Domainslib.Task 모듈을 통해 그린 스레드를 지원한다.
* Occam은 커뮤니케이팅 시퀜셜 프로세스의 기원 때문에 스레드 대신 프로세스라는 용어를 선호한다.
* 펄은 코루틴을 통해 그린 스레드를 지원한다.
* PHP는 파이버와 코루틴을 통해 그린 스레드를 지원한다.
* 래킷 (Places를 통해 네이티브 스레드도 사용 가능)
* 버전 1.9 이전의 루비
* Concurrent ML의 SML/NJ 구현
* 스몰토크 (대부분의 방언: 스퀵, VisualWorks, GNU Smalltalk 등)
* 스택리스 파이썬은 마이크로 스레드(태스클릿이라고 함)를 통해 선점형 멀티태스킹 또는 협력적 멀티태스킹을 지원한다.
* Tcl은 코루틴과 이벤트 루프를 가지고 있다.

얼랭 가상 머신에는 그린 프로세스라고 불릴 만한 것이 있다. 이들은 운영체제 프로세스와 유사하지만(스레드처럼 상태를 공유하지 않는다) 얼랭 런타임 시스템(erts) 내에서 구현된다. 이들은 때때로 그린 스레드라고 불리지만, 표준 그린 스레드와는 상당한 차이가 있다.

GHC 하스켈의 경우, 구성 가능한 타임아웃 후 첫 번째 할당에서 컨텍스트 전환이 발생한다. GHC 스레드는 수명 동안 하나 이상의 OS 스레드에서 실행될 수도 있으며(GHC 스레드와 OS 스레드 간에는 다대다 관계가 있다), 이는 대칭형 다중 처리 머신에서 병렬 처리를 가능하게 하면서도 사용 가능한 코어 수에 필요한 것보다 더 많은 비용이 드는 OS 스레드를 생성하지 않는다.

대부분의 스몰토크 가상 머신은 평가 단계를 세지 않지만, VM은 외부 신호(예: 타이머 만료 또는 I/O 사용 가능)에 따라 실행 중인 스레드를 선점할 수 있다. 일반적으로 라운드 로빈 스케줄링이 사용되어, 주기적으로 깨어나는 고우선순위 프로세스가 효과적으로 시분할 선점을 구현한다.

```smalltalk
[
    [(Delay forMilliseconds: 50) wait] repeat
 ] forkAt: Processor highIOPriority
```

QKS 스몰토크와 같은 다른 구현은 항상 시분할 방식이다. 대부분의 그린 스레드 구현과 달리 QKS는 우선순위 역전 방지도 지원한다.

## 자바 가상 머신의 가상 스레드와의 차이점

가상 스레드는 자바 19에서 미리보기 기능으로 도입되었고 자바 21에서 안정화되었다. 가상 스레드와 그린 스레드의 중요한 차이점은 다음과 같다.

* 가상 스레드는 기존 (비가상) 플랫폼 스레드 및 스레드 풀과 공존한다.
* 가상 스레드는 추상화를 보호한다.
** 그린 스레드와 달리 가상 스레드에서 슬립 상태에 들어가도 기본 캐리어 스레드가 블록되지 않는다.
** 스레드 로컬 변수 사용은 강조되지 않으며, 스코프 값은 더 가벼운 대안으로 제안된다.
* 가상 스레드는 JVM의 특수 `jdk.internal.vm.Continuation` 클래스 지원을 활용하여 저렴하게 일시 중단 및 재개될 수 있다.
* 가상 스레드는 블로킹 호출을 처리할 때 가능한 경우 캐리어 스레드에서 투명하게 분리되며, 그렇지 않은 경우 플랫폼 스레드 수를 늘려 보상한다.

## 같이 보기
* Async/await
* 경량 프로세스
* 코루틴
* 자바 가상 머신
* 글로벌 인터프리터 락
* 파이버 (컴퓨터 과학)
* GNU Portable Threads
* Protothreads

## 각주

## 외부 링크
* "Four for the ages", 그린 스레드에 대한 JavaWorld 기사
* Java 스레드 FAQ의 그린 스레드

분류:자바 플랫폼
분류:스레드