其他分享
首页 > 其他分享> > LeetCode Go 并发题详解:交替打印字符串

LeetCode Go 并发题详解:交替打印字符串

作者:互联网

原文地址:https://mp.weixin.qq.com/s/K032xlARjiyS8ecJrqZXaA

本题 LeetCode 链接:

https://leetcode.com/problems/fizz-buzz-multithreaded/

本题题目

给定一个数列从 1 ~ n,依序输出,但是:

实战要求:使用 4 个执行线程实现一个多执行线程版本。一个 FizzBuzz 的 instance 要被传递到以下四个执行线程中:

本题考核难点?判断责任去中心化!

我一开始认为「这题没什么难的嘛~还不就那些套路再用一次!」,所以最早的实现版本,是写了一个中心控管的 goroutine,判断整除条件后,再把输出任务透过 channel 发派给其他 goroutine A, B, C, D。

直到我为了分享这题,将英文题目翻译为中文的时候,才发现自己误解题目了(尴尬)!题目真正的要求更困难,要各个 goroutine 自行负担检查整除条件的责任。所以只好重写 XD

在过去的 LeetCode Concurrency 详解中,我提到过很多次:

goroutine 若不刻意控制,将无法保证执行的先后顺序,因此本题就是要考核对 goroutine 顺序控制的能力。

但前面几题的解法,大多是把判断责任中心化,方便控管顺序。这次,与前面几题不同的是,这一题要求把判断责任分散到 thread A, B, C 中,所以每个 goroutine 也无法准确得知下一个要接棒的 goroutine 是哪一个?这样的顺序控制会由于分散化,变得更加困难。

By the way,我还解过「DiningPhilosophers」这一题用的就是去中心化方法,但目前还没写那一题详解。

package main
import (     "fmt"     "runtime"     "sync"     "time" )
type FizzBuzz struct {     n int     wg *sync.WaitGroup     streamBaton chan int }
func (this *FizzBuzz) PrintLoop(passCondition func(int) bool, printString func(int)) {     defer this.wg.Done()
    for i := 0; i <= this.n; i++ {         if passCondition(i) {             nextNum := <-this.streamBaton //接棒             if i == nextNum {                 printString(i)                 this.streamBaton <- i + 1 //交棒             } else {                 this.streamBaton <- nextNum //把數字還回去                 i--             }             runtime.Gosched()         }     } }
func (this *FizzBuzz) PrintFizz() {     PassCondition := func(i int) bool { return (0 == i%3) && (0 != i%5) }     PrintString := func(i int) { fmt.Printf("Fizz(%d), ", i) }
    this.PrintLoop(PassCondition, PrintString) }
func (this *FizzBuzz) PrintBuzz() {     PassCondition := func(i int) bool { return (0 != i%3) && (0 == i%5) }     PrintString := func(i int) { fmt.Printf("Buzz(%d), ", i) }
    this.PrintLoop(PassCondition, PrintString) }
func (this *FizzBuzz) PrintFizzBuzz() {     PassCondition := func(i int) bool { return 0 == i%(3*5) }     PrintString := func(i int) { fmt.Printf("FizzBuzz(%d), ", i) }
    this.PrintLoop(PassCondition, PrintString) }
func (this *FizzBuzz) PrintNumber() {     PassCondition := func(i int) bool { return (0 != i%3) && (0 != i%5) }     PrintString := func(i int) { fmt.Printf("%d, ", i) }
    this.PrintLoop(PassCondition, PrintString) }
func main() {     start := time.Now()
    for testCase := 0; testCase <= 20; testCase++ {
        fizzbuzz := &FizzBuzz{             n: testCase,             wg: &sync.WaitGroup{},             streamBaton: make(chan int, 1),         }
        fizzbuzz.wg.Add(4)         go fizzbuzz.PrintFizz()         go fizzbuzz.PrintBuzz()         go fizzbuzz.PrintFizzBuzz()         go fizzbuzz.PrintNumber()         fizzbuzz.streamBaton <- 0 //啟動交棒         fizzbuzz.wg.Wait()         close(fizzbuzz.streamBaton)
        fmt.Println() //這個 Test Case 結束了,換行。     }
    spentTime := time.Now().Sub(start)     fmt.Println("Spent time:", spentTime) }

标签:PassCondition,int,PrintString,fizzbuzz,详解,func,Go,LeetCode,FizzBuzz
来源: https://www.cnblogs.com/smallleiit/p/12640550.html