LoginSignup
0
0

More than 5 years have passed since last update.

golang で semaphore

Last updated at Posted at 2017-11-07

はじめに

  • 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 {
    // エラー処理
  }

}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0