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

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

本题 LeetCode 链接:

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

本题题目

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

  • 如果 n 可以被 3 整除,输出 "fizz"
  • 如果 n 可以被 5 整除,输出 "buzz"
  • 如果 n 同时可以被 3 与 5 整除,输出 "fizzbuzz"

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

  • Thread A 会调用 fizz()     以检查 n 是否可以被    3 整除?若可以就输出 fizz
  • Thread B 会调用 buzz()     以检查 n 是否可以被    5 整除?若可以就输出 buzz
  • Thread C 会调用fizzbuzz() 以检查 n 是否可以被 3, 5 整除?若可以就输出 fizzbuzz
  • Thread D 会调用 number()   照常输出原本数字 n

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

我一开始认为「这题没什么难的嘛~还不就那些套路再用一次!」,所以最早的实现版本,是写了一个中心控管的 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)

}

原文地址:https://www.cnblogs.com/smallleiit/p/12640550.html

时间: 2024-11-06 07:28:45

LeetCode Go 并发题详解:交替打印字符串的相关文章

【leetcode】Edit Distance 详解

下图为TI C6xx DSP Nyquist总线拓扑图,总线连接了master与slave,提供了高速的数据传输.有很多种速率不同的总线,如图中的红色方框,最高速总线为CPU/2 TeraNet SCR(即VBUSM SCR),带宽为256bit,其他低速总线为CPU/3,CPU/6,带宽参考图中所示.总线之间用Bridge(桥)连接,作用包括转换总线的速率,使之与所流向总线的速率相同等. 在具体应用中,各种速率的总线完全可以满足复杂的数据传输,而数据传输的瓶颈往往在于连接总线之间的Bridge

200道历年逻辑推理真题详解

200道历年逻辑推理真题详解 01.粮食可以在收割前在期货市场进行交易.如果预测谷物产量不足,谷物期货价格就会上升:如果预测谷物丰收,谷物期货价格就会下降.今天早上,气象学家们预测从明天开始谷物产区里会有非常需要的降雨.因为充分的潮湿对目前谷物的存活非常重要,所以今天的谷物期货价格会大幅下降. 下面哪个,如果正确,最严重地削弱了以上的观点? A.在关键的授粉阶段没有接受足够潮湿的谷物不会取得丰收. B.本季度谷物期货价格的波动比上季度更加剧烈. C.气象学家们预测的明天的降雨估计很可能会延伸到谷

关于SQL的几道小题详解

关于SQL的几道小题详解 当我们拿到题目的时候,并不是急于作答,那样会得不偿失的,而是分析思路,采用什么方法,达到什么目的,还要思考有没有简单的方法或者通用的方法等等,这样才会达到以一当十的效果,这样的惯性思维其实早在我们度高中的时候就被领教了,所谓“万变不离其宗”吧.以下各题来自日常所见,或QQ群,或面试题,或博客园. 题目一:如下表所示,现需要按照收款员统计收款和退款合计金额. 实现结果需如下显示: 分析:想要的结果(记为表B)和源数据(记为表A)相比,有共同的列(收款员),不同的是表A的金

最小公倍数 【杭电-HDOJ-1108】 附题+详解

/* 最小公倍数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 32933    Accepted Submission(s): 18398 Problem Description 给定两个正整数,计算这两个数的最小公倍数. Input 输入包含多组测试数据,每组只有一行,包括两个不大于1000的正整数. Output 对于每个测试用

《信息系统项目管理师软考辅导——3年真题详解与全真模拟》主要创新点、关注点

<信息系统项目管理师软考辅导--3年真题详解与全真模拟>主要创新点.关注点 新增2014年5月.11月两份真题试卷的360°透彻解析: 更新2013年5月.11月真题试卷的解析: 紧扣考纲,基于历年真题分析,心血创作了一套全新的全真模拟卷: 与时俱进创作了部分前沿信息技术(例如,4G技术.云数据中心.大数据技术等).法规标准的新题,并更新至各份闯关密卷中: 细致地订正了前一版书籍在编写.校对.排版.印刷等环节中所存在的错漏之处(例如,部分语句表述不够准确到位,部分数据上标排版错位等问题),对待

《系统集成项目管理工程师软考辅导——3年真题详解与全真模拟》主要创新点、关注点

<系统集成项目管理工程师软考辅导--3年真题详解与全真模拟>主要创新点.关注点 新增2014年5月.11月两份真题试卷的360°透彻解析: 更新2013年5月.11月真题试卷的解析: 紧扣考纲,基于历年真题分析,心血创作了一套全新的全真模拟卷: 与时俱进创作了部分前沿信息技术(例如,4G技术.云数据中心.大数据技术等).法规标准的新题,并更新至各份闯关密卷中: 细致地订正了前一版书籍在编写.校对.排版.印刷等环节中所存在的错漏之处(例如,部分语句表述不够准确到位,部分数据上标排版错位等问题),

《网络工程师软考辅导——3年真题详解与全真模拟》主要创新点、关注点

"质量第一,开拓创新"是编写这套考试辅导用书的指导思想:出版精品是我们坚持不懈的奋斗目标! <网络工程师软考辅导--3年真题详解与全真模拟>主要创新点.关注点 新增2014年5月.11月两份真题试卷的360°透彻解析: 更新2013年5月.11月真题试卷的解析: 紧扣考纲,基于历年真题分析,心血创作了一套全新的全真模拟卷: 与时俱进创作了部分前沿信息技术(例如,4G技术.云数据中心.大数据技术等).法规标准的新题,并更新至各份闯关密卷中: 细致地订正了前一版书籍在编写.校对

求平均成绩 【杭电-HDOJ-2023】 附题+详解

/* 求平均成绩 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 62086    Accepted Submission(s): 14888 Problem Description 假设一个班有n(n<=50)个学生,每人考m(m<=5)门课,求每个学生的平均成绩和每门课的平均成绩,并输出各科成绩均大于等于平均成绩的学生数量. In

分享软件设计师教程第二三四版本+真题详解+其他考试资料下载

软件设计师教程+真题详解+其他考试资料,教程有第二版第三版第四版,带完整目录. 下载地址:网盘下载 原文地址:https://www.cnblogs.com/milugogo/p/12243121.html