執行緒模型

奇蹟師發表於2021-09-23

執行緒模型

  • 最近在寫有關 go 的執行緒,但是突然一下子就卡住了,之前明明看過很多文章,也寫過協程池,為什麼一到實戰就不行了呢,好吧,其實是寫的不多,但是快速上手也很重要,為什麼不偷懶下直接套模板呢,以下是我總結的一些可以直接套用的簡易模板

前置知識

  • gorontine 協程
  • channel 通道

快速開始

  1. 一個十分簡單的例子
func main() {
    // 使用 sync.WaitGroup 來替代 time.Sleep()
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Println("hello")
    }()
    wg.Wait()
}

嘗試開三個協程,一個生產者,一個消費者,生產者負責組裝傳送資訊,消費者負責接收計算

// producer 負責組裝傳送資訊func producer(nums ...int) <-chan int {
   inCh := make(chan int, len(nums))
   go func() {
      defer close(inCh)
      for _, num := range nums {
         inCh <- num
      }
   }()
   return inCh
}

// consumer 消費者func consumer(inCh <-chan int) <-chan int {
   outCh := make(chan int, len(inCh))
   go func() {
      defer close(outCh)
      for in := range inCh {
         outCh <- in*in
      }
   }()
   return outCh
}

func main() {
   // 將資料組裝為通道 -- 意味著可以被多組消費
  in := producer(1, 2, 3, 4)
   // 進行消費
  out := consumer(in)
   // 列印輸出
  for i:= range out {
      fmt.Println(i)
   }
}

考慮多種情況

1. M個接收者和一個傳送者,傳送者通過關閉用來傳輸資料的通道來傳遞傳送結束訊號


type mc struct {
    cond *sync.Cond
    done bool
}

func New() *mc {
    return &mc{
        cond: sync.NewCond(&sync.Mutex{}),
        done: false,
    }
}

// producer 一個傳送者
func (m *mc) producer(nums ...int) <-chan int {
    inCh := make(chan int, len(nums))
    go func() {
        m.cond.L.Lock()
        defer func() {
            close(inCh)
            m.cond.L.Unlock()
            m.cond.Broadcast()
            m.done = true
        }()
        for _, num := range nums {
            inCh <- num
        }
    }()
    return inCh
}

func (m *mc) consumer(inCh <-chan int) <-chan int {
    outCh := make(chan int, len(inCh))
    go func() {
        m.cond.L.Lock()
        defer func() {
            defer m.cond.L.Unlock()
            close(outCh)
        }()

        for !m.done {
            m.cond.Wait()
        }
        for ch := range outCh {
            outCh <- ch
        }
    }()
    return inCh
}

func merge(chs ...<-chan int, ) <-chan int {
    var wg sync.WaitGroup
    // 將所有資料最後集中到一個通道中
    outCh := make(chan int, len(chs))

    // 將所有資料回收
    collect := func(in <-chan int) {
        defer wg.Done()
        for n := range in {
            // 將資料傳入通道
            outCh <- n
        }
    }

    wg.Add(len(chs))
    for _, ch := range chs {
        go collect(ch)
    }
    go func() {
        wg.Wait()
        close(outCh)
    }()

    return outCh
}

func main() {
    m := New()
    inCh := m.producer(1, 2, 3, 4, 5, 6)
    out1 := m.consumer(inCh)
    out2 := m.consumer(inCh)
    out3 := m.consumer(inCh)

    for i := range merge(out1, out2, out3) {
        fmt.Println(i)
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章