@Golang有意义的问题
和尚搬家
从前,有三个和尚,需要搬家,唯一的要求是要保证搬家前后房内物品布局一致,然后我编不下去了…
问
如何使用3个goroutine是由1-100的有序输出?
分析
问题的核心在于如何保证在并发条件下的有序输出。
主动控制式
package main
import (
"fmt"
"sync"
"time"
)
func main() {
q := make(chan int)
wg := new(sync.WaitGroup)
wg.Add(1)
go func(wg *sync.WaitGroup, q chan<- int) {
defer wg.Done()
defer close(q)
for i := 1; i <= 100; i++ {
q <- i
time.Sleep(time.Microsecond) // 利用休眠实现对生产者的控制,但这种方案不可靠
}
}(wg, q)
for i := 0; i < 3; i++ {
wg.Add(1)
go func(wg *sync.WaitGroup, q <-chan int) {
defer wg.Done()
for {
if v, ok := <-q; ok {
fmt.Println(v)
} else {
return
}
}
}(wg, q)
}
wg.Wait()
}
// 利用WaitGroup实现安全退出,使生产者休眠来进行控制,但是如果消费者的操作是耗时是不可靠谱的,就会变得不可靠
package main
import (
"fmt"
"time"
)
func print(ch <-chan int){
for{
fmt.Println(<-ch)
}
}
func main() {
ch0 :=make(chan int)
ch1 :=make(chan int)
ch2 :=make(chan int)
go print(ch0)
go print(ch1)
go print(ch2)
for i:=1; i<101; i++{
switch{
case i%3 == 0:
ch0 <- i
case i%3 == 1:
ch1 <- i
case i%3 == 2:
ch2 <-i
}
time.Sleep(time.Microsecond)
}
}
// 利用for循环实现安全退出,同样是使生产者休眠来进行控制,但是如果消费者的操作是耗时是不可靠谱的,就会变得不可靠
抢占式
package main
import (
"fmt"
"sync"
"time"
)
func main() {
q := make(chan int)
wg := new(sync.Mutex)
go func( q chan<- int) {
defer close(q)
for i := 1; i <= 100; i++ {
q <- i
}
}(q)
for i := 0; i < 3; i++ {
go func(wg *sync.Mutex, q <-chan int) {
for {
wg.Lock()
if v, ok := <-q; ok {
fmt.Println(v)
wg.Unlock()
} else {
wg.Unlock()
return
}
}
}(wg, q)
}
time.Sleep(time.Second) // 安全退出
}
// 使用互斥锁阻塞其他协程来实现抢占,使用休眠实现安全退出,这种方案是可靠的,但最好能够使用WaitGroup来实现安全退出
package main
import (
"fmt"
"time"
)
func main() {
a := 0
fn := func() int {
a++
return a
}
ch := make(chan int, 1)
defer close(ch)
for i := 0; i < 3; i++ {
go func() {
for {
ch <- 1
n := fn()
if n > 100 {
break
}
fmt.Println(n)
<-ch
}
}()
}
time.Sleep(time.Second) // 安全退出
}
// 使用管道来塞其他协程来实现抢占,使用休眠实现安全退出,这种方案是可靠的,同理,最好能够使用WaitGroup来实现安全退出