房山富阳网站建设,凡客优品家居,wordpress怎么还原,招标网有哪些协程面试题交替打印奇数和偶数N个协程打印1到maxVal交替打印字符和数字交替打印字符串三个协程打印ABCChannel练习交替打印奇数和偶数
下面让我们一起来看看golang当中常见的算法面试题 使用两个goroutine交替打印1-100之间的奇数和偶数, 输出时按照从小到大输出. 方法一…
协程面试题交替打印奇数和偶数N个协程打印1到maxVal交替打印字符和数字交替打印字符串三个协程打印ABCChannel练习交替打印奇数和偶数
下面让我们一起来看看golang当中常见的算法面试题 使用两个goroutine交替打印1-100之间的奇数和偶数, 输出时按照从小到大输出. 方法一使用无缓冲的channel进行协程间通信
package mainimport (fmtsync
)// PrintOddAndEven1 /*
func PrintOddAndEven1() {//方法一,使用无缓冲的channel进行通信var wg new(sync.WaitGroup) //注意这里需要是指针go语言当中都是值传递wg.Add(2)ch : make(chan struct{}) //无缓冲channeldefer close(ch)maxVal : 100go func() {defer wg.Done()for i : 1; i maxVal; i {ch - struct{}{}if i%2 1 { //奇数fmt.Printf(the odd is %d\n, i)}}}()go func() {defer wg.Done()for i : 1; i maxVal; i {-ch //从管道当中读取一个数据if i%2 0 { //偶数fmt.Printf(the even is %d\n, i)}}}()wg.Wait()}
func main() {PrintOddAndEven1()fmt.Println(over)
}
下面博主来解释一下这个的原理 首先因为变量ch是一个无缓冲的channel, 所以只有读写同时就绪时才不会阻塞。所以两个goroutine会同时进入各自的 if 语句此时 i 是相同的但是此时只能有一个 if 是成立的不管goroutine快都会由于读channel或写channel导致阻塞因此程序会交替打印1-100且有顺序。
方法二使用有缓冲的channel
func PrintOddAndEven2() {var wg new(sync.WaitGroup) //注意这里需要是指针go语言当中都是值传递wg.Add(2)oddChan : make(chan struct{}, 1)eveChan : make(chan struct{}, 1)defer close(oddChan)defer close(eveChan)oddChan - struct{}{}maxVal : 20go func() { //奇数协程defer wg.Done()for i : 1; i maxVal; i 2 {-oddChanfmt.Printf(the odd print %d\n, i)eveChan - struct{}{} //通知偶数协程}}()go func() {//偶数协程defer wg.Done()for i : 2; i maxVal; i 2 {-eveChanfmt.Printf(the even print %d\n, i)oddChan - struct{}{} //通知奇数协程可以打印了}}()wg.Wait()}func main() {PrintOddAndEven2()fmt.Println(over)
}第二个方法使用这个有缓冲的channel。有缓冲的channel当容量没有达到上限时写入不会阻塞在这里奇数协程的channel容量为1我们提前给他写入了一个数据因此当偶数和奇数协程都开始读取数据时首先读取到数据的是奇数协程奇数协程打印完之后在通知偶数协程打印偶数协程打印完成之后在通知奇数协程重复下去就实现了交替打印的效果。
N个协程打印1到maxVal
题目描述非常的简单就是N个协程交替打印1到maxVal。比如N3,maxVal是这个100效果应该是第一个协程打印1第二个协程打印2第三个协程打印3第一个协程打印4这样的效果。 这道题看起来非常的复杂博主第一次看到这个题的时候也感觉很复杂但是仔细想一下其实并没有那么复杂和上面两题的解题思路是一样的。下面我们看看这个代码如何实现
package mainimport (fmtsync
)func main() {maxVal : 10res : 0 //用于打印数字N : 3 //协程的数量exitChan : make(chan struct{}) //用于退出chanArr : make([]chan struct{}, N)for i : 0; i N; i {//使用无缓冲的channelchanArr[i] make(chan struct{}, 1)}num : 0 //记录轮到那个协程开始打印了chanArr[0] - struct{}{}for i : 0; i N; i {go func(i int) {for {-chanArr[i]if res maxVal {exitChan - struct{}{}break}fmt.Printf(第%d个协程打印%d\n, i, res)if num N-1 {//已经循环一轮了轮到第0个协程打印数据了num 0} else {num}reschanArr[num] - struct{}{} //第num个协程可以打印数据了}}(i)}-exitChanfor i : 0; i N; i {close(chanArr[i]) //将管道全部关闭否则会有协程泄漏}}其实也非常的简单也是利用channel来进行这个协程之间的通信由于是N个协程之间进行通信所以了我们定义一个channel的切片首先往第一个channel当中写入一个数据其他管道没有写入数据那么最先打印的一定是这个第一个协程然后我们在利用一个计数器通知其他协程打印。最后需要注意的是主协程退出时需要将管道全部关闭否则其他协程一致阻塞在那里就会引起协程泄漏,就只能等到gc的时候才能回收。
交替打印字符和数字
问题描述: 使用两个 goroutine 交替打印序列一个 goroutinue 打印数字 另外一个goroutine打印字母 最终效果如下 12AB34CD56EF78GH910IJ 。 如果铁子们上面两题会了那么这道题就是有手就行的那种和第一道题没有啥区别
func main() {numChan : make(chan struct{}, 1)chChan : make(chan struct{}, 1)defer close(numChan)defer close(chChan)var wg sync.WaitGroupwg.Add(2)numChan - struct{}{}go func() {defer wg.Done()for num : 1; num 26; num {-numChanfmt.Printf(%d, num)chChan - struct{}{}}}()go func() {defer wg.Done()for ch : A; ch Z; ch {-chChanfmt.Printf(%s, string(ch))numChan - struct{}{}}}()wg.Wait()}
同样的也是利用这个channe进行通信利用有缓冲的channel进行通信。当然也能使用这个无缓冲的channel进行通信
func main() {numChan : make(chan struct{})defer close(numChan)var wg sync.WaitGroupwg.Add(2)go func() {defer wg.Done()for num : 1; num 26; num {numChan - struct{}{}fmt.Printf(%d, num)}}()go func() {defer wg.Done()for ch : A; ch Z; ch {-numChanfmt.Printf(%s, string(ch))}}()wg.Wait()交替打印字符串
题目描述给定一个字符串使用两个协程交替打印它。 如果老铁们上面的拿到题都会了这道题不就是和第一道题是这个一模一样的吗废话不多说直接上代码 方法一使用无缓冲的channel func main() {chChan : make(chan struct{})defer close(chChan)var wg new(sync.WaitGroup)wg.Add(2)str : hello worldN : len(str)go func() {defer wg.Done()for i : 0; i N; i {chChan - struct{}{}if i%2 0 {fmt.Println(string(str[i]))}}}()go func() {defer wg.Done()for i : 0; i N; i {-chChanif i%2 1 {fmt.Println(string(str[i]))}}}()wg.Wait()}当然也可以使用有缓冲的channel在这里铁子们可以自行编写上面写的太多了。
三个协程打印ABC
题目描述使用三个协程分别打印A,B,C打印这个100次。 本题的难度和上面那几个题完全是一个货色我们可以使用三个有缓冲的channel就可以达到目的了。具体细节请看代码
package mainimport (fmtsync
)func main() {Achan : make(chan struct{}, 1)Bchan : make(chan struct{}, 1)Cchan : make(chan struct{}, 1)defer close(Achan)defer close(Bchan)defer close(Cchan)Achan - struct{}{}counter : 0maxVal : 10exitChan : make(chan struct{}) //用于退出go func() {for {-Achanif counter maxVal {exitChan - struct{}{}break}fmt.Printf(%s , A)counterBchan - struct{}{}}}()go func() {for {-Bchanif counter maxVal {exitChan - struct{}{}break}fmt.Printf(%s , B)counterCchan - struct{}{}}}()go func() {for {-Cchanif counter maxVal {exitChan - struct{}{}break}fmt.Printf(%s , C)counterAchan - struct{}{}}}()-exitChan
}在这里需要注意的点是我们需要close掉这个管道当达到临界值时主协程退出但是defer方法会执行这个时候管道一关闭所有协程都会收到退出信号另外两个阻塞在那里的协程就会退出这样就没有这个协程泄漏了。
##并发将多个文件合并到一个文件当中 MergeFile 把多个文件合成一个文件并发实现子协程优雅退出。采用并发的方式 本题的解题思路同样的也非常的简单我们可以定义一个管道并发的读取文件写入到管道当中然后再并发的写入到文件当中。非常的简单
package mainimport (bufiofmtioosstrconvsync
)// MergeFile 把多个文件合成一个文件并发实现子协程优雅退出var fileChan make(chan string, 10000)
var writeFish make(chan struct{})
var wg sync.WaitGroupfunc readFile(fileName string) {fin, err : os.Open(fileName)if err ! nil {fmt.Println(err.Error())return}defer fin.Close()defer wg.Done()reader : bufio.NewReader(fin)for {line, err : reader.ReadString(\n) //注意已经包含换行符了if err ! nil {if err io.EOF {if len(line) 0 {line \nfileChan - line}break} else {fmt.Println(err)break}} else if line \r\n {fmt.Println(进来)continue} else {fileChan - line}}}
func writeFile(fileName string) {fout, err : os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)if err ! nil {fmt.Println(err)return}defer fout.Close()defer func() {close(writeFish)}()writer : bufio.NewWriter(fout)//LOOP:// for {// select {// case -readFish:// close(fileChan)//注意需要关闭因为已经没有人往里面写了// for line:range fileChan{// writer.WriteString(line) //读取时候已经包含换行符了// }// break LOOP// case line : -fileChan:// writer.WriteString(line) //读取时候已经包含换行符了// }//// }for {if line, ok : -fileChan; ok {if line ! \r\n {writer.WriteString(line)}} else {break}}writer.Flush() //刷新}func main() {wg.Add(3)for i : 1; i 3; i {fileName : Dir/ strconv.Itoa(i)go readFile(fileName)}go writeFile(Dir/merge)wg.Wait()close(fileChan)-writeFish}
Channel练习
启动一个协程生成100个数发送到ch1管道当中再启动一个协程从ch1当中取值然后计算平方将其放入ch2管道当中主协程打印
package mainimport (fmtsync
)var wg sync.WaitGroupfunc f1(ch1 chan int) {defer wg.Done()for i : 0; i 50; i {ch1 - i}close(ch1)
}
func f2(ch2 chan int, ch1 chan int) {defer wg.Done()defer close(ch2)for x : range ch1 {ch2 - x * x}
}
func main() {wg.Add(2)a : make(chan int, 50)b : make(chan int, 50)go f1(a)go f2(b, a)wg.Wait()for x : range b {fmt.Println(x)}}