참고 :
많은 일시적으로 개체에 대한 빠르고 좋은 구현 sync.Pool
를 사용하는 것이 좋습니다. 그러나 sync.Pool
은 풀링 된 개체가 유지된다는 것을 보증하지 않습니다. 그 문서에서 인용 :
풀 에 저장된 모든 항목을 통지없이 언제든지 자동으로 제거 할 수있다. 이 때 풀이 유일한 참조를 보유하면 항목의 할당이 취소 될 수 있습니다.
그래서 당신은 쓰레기 (귀하의 경우에 따라하는 것이 더 할당이 발생할 수 있음) 채널의 버퍼에 값이 아니기 때문에, 아래 제시된 해결책은, 더 나은 수집 얻을 수있는 Pool
에서 개체를하지 않으려면 쓰레기 수거. 객체가 실제 메모리 풀만큼 큰 경우 풀 채널의 오버 헤드가 상각됩니다.
가장 간단한 메모리 풀 "구현"은 버퍼링 된 채널입니다.
큰 개체의 메모리 풀을 원한다고 가정 해 보겠습니다. 비싼 객체의 값에 대한 포인터를 보유한 버퍼링 된 채널을 만들고 필요할 때마다 풀 (채널)에서 값을받습니다. 사용이 끝나면 다시 풀에 넣으십시오 (채널을 보내십시오). 실수로 (예를 들어 공황 상태 인 경우) 객체를 잃어 버리지 않도록하려면 다시 넣을 때 defer
문을 사용하십시오.
은의 우리의 큰 객체의 형태로 사용하자 : 풀을 생성
는
type BigObject struct {
Id int
Something string
}
입니다 : 풀의
pool := make(chan *BigObject, 10)
크기는 단순히 채널의 버퍼의 크기입니다. 많은 goroutines하여 풀을 사용
for i := 0; i < cap(pool); i++ {
bo := &BigObject{Id: i}
pool <- bo
}
: 비싼 객체의 포인터 풀 (이, 마지막에 메모를 선택 참조한다)를 작성
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
bo := <-pool
defer func() { pool <- bo }()
fmt.Println("Using", bo.Id)
fmt.Println("Releasing", bo.Id)
}()
}
wg.Wait()
는 Go Playground에 시도 .
"풀링 된"모든 개체가 사용 중이면이 구현이 차단됩니다.
var bo *BigObject
select {
case bo = <-pool: // Try to get one from the pool
default: // All in use, create a new, temporary:
bo = &BigObject{Id:-1}
}
그리고이 경우에는 풀에 다시 넣을 필요가 없습니다 : 당신이하지 않으려면 모두 사용하는 경우, 당신은 새로운 객체를 생성 강제로 select
를 사용할 수 있습니다. 아니면 풀에 공간이 있다면 select
다시 차단하지 않고 풀에 모든 다시 넣어 시도 할 수도 있습니다 :
이
select {
case pool <- bo: // Try to put back into the pool
default: // Pool is full, will be garbage collected
}
주 : 이전에 풀을 작성이
선택 사항입니다. select
을 사용하여 풀에서 값을 가져 오거나 다시 넣으려고하면 풀은 처음에는 비어있을 수 있습니다.
요청간에 정보가 누출되지 않도록해야합니다 (예 : 설정되어 있고 다른 요청에 속한 공유 객체에서 필드와 값을 사용하지 않도록하십시오.
stdlib에는 [sync.Pool'] (https://golang.org/pkg/sync/#Pool)이 있습니다. 그 외에도 "무료 목록"을 구현하는 것은 Go와 관련이없는 기술입니다. – JimB