はじめに
- chan を使った semaphore をループ処理のなかで使っていた
- for 1ループごとに defer したいが func 抜ける時しか実行されない
- そうだ、無名関数で囲もう
セマフォ
type Semaphore struct {
sem chan struct{}
}
func NewSemaphore(size int) *Semaphore {
return &Semaphore{
sem: make(chan struct{}, size),
}
}
func (s *Semaphore) V() {
s.sem <- struct{}{}
}
func (s *Semaphore) P() {
<-s.sem
}
普通にdefer
for {
sem.V()
defer sem.P() // 当然まともに動かない
// 途中で抜ける
if err != nil {
continue
}
// 何か処理
}
無名関数で囲んでみる
for {
func() {
sem.V()
defer sem.P()
// 途中で抜けてもOK
if err != nil {
return
}
// 何か処理
}()
}
Wrap関数にしてみる
type Semaphore struct {
sem chan struct{}
}
func NewSemaphore(size int) *Semaphore {
return &Semaphore{
sem: make(chan struct{}, size),
}
}
func (s *Semaphore) V() {
s.sem <- struct{}{}
}
func (s *Semaphore) P() {
<-s.sem
}
func (s *Semaphore) Wrap(f func() error) chan error {
errChan := make(chan error, 1)
s.sem <- struct{}{}
errChan <- f()
close(errChan)
<-s.sem
return errChan
}
最終形
for {
ec := sem.Wrap(func() error {
// 途中で抜けてもOK
if err != nil {
return
}
// 何か処理
})
if err := <- ec; err != nil {
// エラー処理
}
}