스레드 풀

대기 중인 태스크(파란색)와 완료된 태스크(노란색)가 있는 샘플 스레드 풀(녹색 상자) 컴퓨터 프로그래밍에서 **스레드 풀**(Thread pool)은 컴퓨터 프로그램에서 병행 실행을 달성하기 위한 소프트웨어 디자인 패턴이다. 종종 **복제 작업자** 또는 **작업자 그룹 모델**이라고도 불리는Garg, Rajat P. & Sharapov, Ilya Techniques for Optimizing Applications - High Performance Computing Prentice-Hall 2002, p. 394 스레드 풀은 감독 프로그램에 의해 병행 실행을 위해 할당될 태스크를 기다리는 여러 스레드를 유지한다. 스레드 풀을 유지함으로써 이 모델은 성능을 향상시키고 짧은 수명 태스크를 위해 스레드를 자주 생성하고 파괴하는 데 따른 실행 지연을 방지한다.page=209 또 다른 장점은 사용 가능한 스레드보다 적은 스레드를 사용할 때 시스템 부하를 제한하는 기능이다. 사용 가능한 스레드 수는 실행 완료 후 병렬 태스크 큐와 같이 프로그램에 사용 가능한 컴퓨팅 리소스에 맞춰 조정된다.
# 성능
스레드 풀의 크기는 태스크 실행을 위해 예비로 유지되는 스레드 수이다. 일반적으로 애플리케이션의 튜닝 가능한 매개변수이며, 프로그램 성능을 최적화하기 위해 조정된다. 최적의 스레드 풀 크기를 결정하는 것은 성능 최적화에 중요하다. 각 태스크에 대해 새 스레드를 생성하는 것보다 스레드 풀의 한 가지 이점은 스레드 생성 및 파괴 오버헤드가 풀의 초기 생성으로 제한되어 더 나은 성능과 더 나은 시스템 안정성을 가져올 수 있다는 것이다. 스레드 및 관련 리소스를 생성하고 파괴하는 것은 시간 측면에서 비용이 많이 드는 프로세스일 수 있다. 그러나 예비 스레드 수가 과도하면 메모리가 낭비되고, 실행 가능한 스레드 간의 컨텍스트 스위칭은 성능 저하를 초래한다. 많은 CPU 사이클이 소요될 수 있는 다른 네트워크 호스트와의 소켓 연결은 두 개 이상의 네트워크 트랜잭션 과정에서 유지되는 스레드와 연결하여 더 효율적으로 유지할 수 있다. 스레드 시작 시간을 제쳐두고서라도 스레드 풀을 사용하는 것이 유용할 수 있다. 수동으로 스레드를 관리할 때보다 훨씬 쉽게 작업을 큐에 넣고, 병행성을 제어하며, 스레드를 더 높은 수준에서 동기화할 수 있는 스레드 풀 구현이 있다.Qt Core 5.13.1date = 2019-09-24 이 경우 사용의 성능 이점은 부차적일 수 있다. 일반적으로 스레드 풀은 단일 컴퓨터에서 실행된다. 그러나 스레드 풀은 전체 처리량을 늘리기 위해 스레드 풀 자체일 수 있는 마스터 프로세스가 다른 컴퓨터의 작업자 프로세스에 작업을 분배하는 서버 팜과 개념적으로 관련이 있다. 처치 곤란 병렬 문제는 이 접근 방식에 매우 적합하다. 스레드 수는 대기 중인 태스크 수에 따라 애플리케이션 수명 동안 동적으로 조정될 수 있다. 예를 들어, 웹 서버는 많은 웹 페이지 요청이 들어오면 스레드를 추가할 수 있고, 요청이 줄어들면 스레드를 제거할 수 있다. 더 큰 스레드 풀을 갖는 비용은 리소스 사용량 증가이다. 스레드를 생성하거나 파괴할 시기를 결정하는 데 사용되는 알고리즘은 전체 성능에 영향을 미친다. * 너무 많은 스레드를 생성하면 리소스가 낭비되고 사용되지 않는 스레드를 생성하는 데 시간이 소요된다. * 너무 많은 스레드를 파괴하면 나중에 다시 생성할 때 더 많은 시간이 필요하다. * 너무 느리게 스레드를 생성하면 클라이언트 성능이 저하될 수 있다(긴 대기 시간). * 너무 느리게 스레드를 파괴하면 다른 프로세스의 리소스가 부족해질 수 있다.
# 언어별 구현
배시에서는 예를 들어 Xargs의 `--max-procs` / `-P`로 구현된다. # Fetch 5 URLs in parallel urls=( "https://example.com/file1.txt" "https://example.com/file2.txt" "https://example.com/file3.txt" "https://example.com/file4.txt" "https://example.com/file5.txt" ) printf '%s\n' "${urls[@]}" | xargs -P 5 -I {} curl -sI {} | grep -i "content-length:" language=enwebsite=www.man7.orgwebsite=www.gnu.org Go에서는 워커 풀이라고 불린다. package main import ( "fmt" "time" ) func worker(id int, jobs <-chan int, results chan<\- int) { for j := range jobs { fmt.Println("worker", id, "started job", j) time.Sleep(time.Second) fmt.Println("worker", id, "finished job", j) results <\- j * 2 } } func main() { const numJobs = 5 jobs := make(chan int, numJobs) results := make(chan int, numJobs) for w := 1; w <= 3; w++ { go worker(w, jobs, results) } for j := 1; j <= numJobs; j++ { jobs <\- j } close(jobs) for a := 1; a <= numJobs; a++ { <-results } } 다음과 같이 출력된다. $ time go run worker-pools.go worker 1 started job 1 worker 2 started job 2 worker 3 started job 3 worker 1 finished job 1 worker 1 started job 4 worker 2 finished job 2 worker 2 started job 5 worker 3 finished job 3 worker 1 finished job 4 worker 2 finished job 5 real 0m2.358s website=gobyexample.comquote=another approach that manages resources well is to start a fixed number of handle goroutines all reading from the request channel. The number of goroutines limits the number of simultaneous calls to processquote=Worker pools are a model in which a fixed number of m workers (implemented in Go with goroutines) work their way through n tasks in a work queue (implemented in Go with a channel). Work stays in a queue until a worker finishes up its current task and pulls a new one off.