Golang如何限制同时执行任务的协程数量

Golang如何限制同时执行任务的协程数量 我正在Coursera上学习Go语言,最后一个练习是实现“哲学家就餐”算法。

  • 5位哲学家可以就餐,每位需要吃3次
  • 同时只能有2位哲学家就餐
  • 共有5根筷子

我想定义一个host函数,用于控制同时只能有2位哲学家就餐。 由于知识有限,我在实现上遇到了困难。 我尝试使用一个通道,并将哲学家发送到通道中,但我仍然不知道/不理解如何限制允许同时就餐的哲学家数量。

非常感谢!

package main

import (
"fmt"
"sync"
"time"
)

type ChopS struct {
    sync.Mutex
}

type Philosopher struct {
    number          int
    leftCs, rightCs *ChopS
}

func (p Philosopher) GetNumber() int {
     return p.number
}

func (p Philosopher) Eat(wg *sync.WaitGroup) {
   for i := 1; i <= 3; i++ {
	p.leftCs.Lock()
	p.rightCs.Lock()
	fmt.Println("starting to eat <", p.number, ">")
	fmt.Println("Finishing eating <", p.number, ">")
	p.leftCs.Unlock()
	p.rightCs.Unlock()
	time.Sleep(2 * time.Second)
   }

}

func NewPhilospher(number int, leftCs, rightCs *ChopS) Philosopher {
   var p Philosopher

   p.number = number
   p.leftCs = leftCs
   p.rightCs = rightCs

  return p
}

func createChops() []*ChopS {
    CSticks := make([]*ChopS, 5)
    for i := 0; i < 5; i++ {
	    CSticks[i] = new(ChopS)
    }
    return CSticks
}

func createPhilosophers() []Philosopher {

    var philos []Philosopher

    CSticks := createChops()
    for i := 0; i < 5; i++ {
	   philos = append(philos, NewPhilospher(i, CSticks[i], CSticks[(i+1)%5]))
    }

    return philos
}

func host() {

   // only 2 Philosophers can eat at the same time
}

func main() {
    philos := createPhilosophers()
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
	    wg.Add(1)
	    go philos[i].Eat(&wg)
    }

   wg.Wait()
}

更多关于Golang如何限制同时执行任务的协程数量的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

更多关于Golang如何限制同时执行任务的协程数量的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


可以使用带缓冲的通道作为信号量来限制并发数量。以下是实现host函数的示例:

func host(philosophers []Philosopher, wg *sync.WaitGroup) {
    // 创建缓冲大小为2的通道,限制同时只有2个哲学家可以就餐
    semaphore := make(chan struct{}, 2)
    
    for i := 0; i < len(philosophers); i++ {
        wg.Add(1)
        go func(p Philosopher) {
            defer wg.Done()
            
            // 获取许可,如果通道已满则阻塞
            semaphore <- struct{}{}
            
            // 哲学家开始就餐
            p.Eat()
            
            // 释放许可
            <-semaphore
        }(philosophers[i])
    }
}

修改主函数使用host函数:

func main() {
    philos := createPhilosophers()
    var wg sync.WaitGroup
    
    host(philos, &wg)
    
    wg.Wait()
}

修改Eat方法去掉WaitGroup参数:

func (p Philosopher) Eat() {
    for i := 1; i <= 3; i++ {
        p.leftCs.Lock()
        p.rightCs.Unlock()
        fmt.Println("starting to eat <", p.number, ">")
        fmt.Println("Finishing eating <", p.number, ">")
        p.leftCs.Unlock()
        p.rightCs.Unlock()
        time.Sleep(2 * time.Second)
    }
}

完整实现示例:

package main

import (
    "fmt"
    "sync"
    "time"
)

type ChopS struct {
    sync.Mutex
}

type Philosopher struct {
    number          int
    leftCs, rightCs *ChopS
}

func (p Philosopher) Eat() {
    for i := 1; i <= 3; i++ {
        p.leftCs.Lock()
        p.rightCs.Lock()
        fmt.Println("starting to eat <", p.number, ">")
        time.Sleep(time.Second)
        fmt.Println("Finishing eating <", p.number, ">")
        p.leftCs.Unlock()
        p.rightCs.Unlock()
        time.Sleep(2 * time.Second)
    }
}

func NewPhilospher(number int, leftCs, rightCs *ChopS) Philosopher {
    return Philosopher{
        number:  number,
        leftCs:  leftCs,
        rightCs: rightCs,
    }
}

func createChops() []*ChopS {
    CSticks := make([]*ChopS, 5)
    for i := 0; i < 5; i++ {
        CSticks[i] = new(ChopS)
    }
    return CSticks
}

func createPhilosophers() []Philosopher {
    var philos []Philosopher
    CSticks := createChops()
    
    for i := 0; i < 5; i++ {
        philos = append(philos, NewPhilospher(i+1, CSticks[i], CSticks[(i+1)%5]))
    }
    return philos
}

func host(philosophers []Philosopher, wg *sync.WaitGroup) {
    semaphore := make(chan struct{}, 2)
    
    for i := 0; i < len(philosophers); i++ {
        wg.Add(1)
        go func(p Philosopher) {
            defer wg.Done()
            semaphore <- struct{}{}
            p.Eat()
            <-semaphore
        }(philosophers[i])
    }
}

func main() {
    philos := createPhilosophers()
    var wg sync.WaitGroup
    
    host(philos, &wg)
    wg.Wait()
}

这个实现使用带缓冲的通道作为计数信号量,缓冲大小设置为2确保同时只有两位哲学家可以就餐。当通道已满时,尝试发送的协程会阻塞,直到有哲学家就餐完毕释放许可。

回到顶部