Tunny는 고루틴 풀을 생성하고 관리하기 위한 Golang 라이브러리로, 동기화 API를 사용하여 임의의 수의 고루틴으로부터의 작업을 제한할 수 있습니다.

당신의 작업이 비동기 소스의 임의의 수로부터 오지만 병렬 처리 능력이 제한될 때, 고정된 고루틴 풀은 매우 유용합니다. 예를 들어, CPU 집약적인 HTTP 요청 작업을 처리할 때, CPU 개수만큼의 사이즈로 풀을 생성할 수 있습니다.

## 설치

```shell
go get github.com/Jeffail/tunny

또는, dep를 사용하여 다음과 같이 설치할 수 있습니다:

dep ensure -add github.com/Jeffail/tunny

사용법

대부분의 경우, 무거운 작업은 단순한 func()로 표현될 수 있으며, 이 경우 NewFunc를 사용할 수 있습니다. HTTP 요청을 CPU 카운팅 예제로 살펴보겠습니다:

package main

import (
	"io/ioutil"
	"net/http"
	"runtime"

	"github.com/Jeffail/tunny"
)

func main() {
	numCPUs := runtime.NumCPU()

	pool := tunny.NewFunc(numCPUs, func(payload interface{}) interface{} {
		var result []byte

		// TODO: 페이로드를 사용하여 CPU 집약적인 작업 수행

		return result
	})
	defer pool.Close()

	http.HandleFunc("/work", func(w http.ResponseWriter, r *http.Request) {
		input, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "내부 오류", http.StatusInternalServerError)
		}
		defer r.Body.Close()

		// 이 작업을 풀에 추가합니다. 이 호출은 동기적이며 작업이 완료될 때까지 차단됩니다.
		result := pool.Process(input)

		w.Write(result.([]byte))
	})

	http.ListenAndServe(":8080", nil)
}

Tunny는 타임아웃도 지원합니다. 위의 Process 호출을 다음 코드로 대체할 수 있습니다:

result, err := pool.ProcessTimed(input, time.Second*5)
if err == tunny.ErrJobTimedOut {
	http.Error(w, "요청 시간 초과", http.StatusRequestTimeout)
}

또한 요청 컨텍스트(또는 기타 컨텍스트)를 사용하여 타임아웃과 데드라인을 처리할 수도 있습니다. 다음 코드로 Process 호출을 대체하면 됩니다:

result, err := pool.ProcessCtx(r.Context(), input)
if err == context.DeadlineExceeded {
	http.Error(w, "요청 시간 초과", http.StatusRequestTimeout)
}

풀 크기 변경

SetSize(int)를 사용하여 Tunny 풀의 크기를 언제든지 변경할 수 있습니다.

pool.SetSize(10) // 10개의 고루틴
pool.SetSize(100) // 100개의 고루틴

이는 다른 고루틴들이 아직 처리 중일 때에도 안전합니다.

상태를 가지는 고루틴

가끔씩, Tunny 풀의 각 고루틴은 자체적인 관리 상태를 필요로 할 수 있습니다. 이 경우, tunny.Worker를 구현해야 하며, 종료, 인터럽트(작업이 시간 초과되고 더 이상 필요하지 않을 경우), 특정 조건이 충족될 때까지 다음 작업의 할당을 차단하는 호출을 포함합니다.

Worker 유형으로 풀을 만들 때, 사용자 정의 구현을 생성하기 위한 생성자를 제공해야 합니다:

pool := tunny.New(poolSize, func() Worker {
	// TODO: 각 고루틴에 대한 상태 할당 수행
	return newCustomWorker()
})

이렇게 하면 Tunny가 풀 크기가 변경될 때 Worker 유형의 생성과 소멸을 정리할 수 있습니다.

순서

대기 중인 작업은 순서대로 처리되는 것이 보장되지 않습니다. 현재의 채널 및 선택 블록 구현 때문에, 대기 중인 작업 스택은 FIFO 큐로 처리될 것입니다. 그러나 이 동작은 사양의 일부가 아니며 의존해서는 안 됩니다.