2022-5-30 实习Day47 1、手工分报-处理方式为空时,前端国际化提示为英文值,placeholder未匹配,问题查找与js代码修改–3小时 100% 2、汇出汇款提交再打回报异常,问题查找与调试修改。打回后提交先删后增,删除失败,定位mapper中的sql语句错误–3小时 100%
Golang编程学习(part 42) 1、channel应用案例1
请完成goroutine和channel协同工作的案例,具体要求:
开启一个writeData协程,向管道intChan中写入50个整数
开启一个readData协程,从管道intChan中读取writeData写入的数据
注意:writeData和readData操作的是同一个管道
主线程需要等待writeData和readData协程都完成工作才能退出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package mainimport ( "fmt" ) func main () { intChan := make (chan int , 100 ) exitChan := make (chan bool , 1 ) go writeData(intChan) go readData(intChan, exitChan) for { _, ok := <-exitChan if !ok { break } } } func writeData (intChan chan int ) { for i := 0 ; i < 100 ; i++ { intChan <- i fmt.Println("writeData " , i) } close (intChan) } func readData (intChan chan int , exitChan chan bool ) { for { v, ok := <-intChan if !ok { break } fmt.Printf("readData 读到的数据=%v\n" , v) } exitChan <- true close (exitChan) }
2、channel应用案例2
启动一个协程,将1-2000的数放入到一个channel中,比如numChan
启动8个协程,从numChan取出数(比如n),并计算1+…+n的值,并存放到resChan
最后8个协程协同完成工作后再遍历resChan,显示结果(如res[1]=1 .. res[10]=55 ..)
注意:考虑resChan chan int是否合适
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package mainimport ( "fmt" "strconv" ) func main () { intChan := make (chan int , 2000 ) resData := make (chan string , 1000 ) exitChan := make (chan bool , 8 ) go writeDa(intChan) for i := 0 ; i < 8 ; i++ { go readDa(intChan, resData, exitChan) } go func () { for i := 0 ; i < 8 ; i++ { <-exitChan } close (resData) }() for { res, ok := <-resData if !ok { break } fmt.Println(res) } } func writeDa (intChan chan int ) { for i := 1 ; i <= 2000 ; i++ { intChan <- i fmt.Println("写入了数据:" , i) } close (intChan) } func readDa (intData chan int , resData chan string , exitChan chan bool ) { for { result := 0 ints, ok := <-intData if !ok { break } for i := 1 ; i <= ints; i++ { result += i } resData <- "result[" + strconv.Itoa(ints) + "]=" + strconv.Itoa(result) } exitChan <- true }
3、goroutine+channel配合完成排序并写入文件
开启一个协程 writeDataToFile,随机生成1000个数据,存放到文件中
当writeDataToFile完成写1000个数据到文件后,让sort协程从文件中读取1000个数据,并完成排序,重新写入到另外一个文件
考察点,协程和管道+文件到综合应用
功能扩展:开10个协程writeDataToFile,每个协程随机生成1000个数据,存放到10个文件中
当10个文件都生成了,让10个sort协程从文件中读取1000个文件,并完成排序,重新写入到10个结果文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 package mainimport ( "bufio" "fmt" "io" "math/rand" "os" "strconv" "strings" "time" ) func main () { boolChannel := make (chan bool , 1 ) filePathChannel := make (chan string , 1 ) go writeDataToFile("mydoc" , boolChannel, filePathChannel) go sort(boolChannel, filePathChannel) for { _, ok := <-boolChannel if !ok { break } } } func sort (boolChannel chan bool , filePathChannel chan string ) { var file *os.File var err error for { pathChannel, ok := <-filePathChannel if !ok { break } file, err = os.Open(pathChannel) } if err != nil { fmt.Println(err) return } reader := bufio.NewReader(file) for { readString, err := reader.ReadString('\n' ) fmt.Println(strings.Trim(readString, "\n" )) if err == io.EOF { break } } } func writeDataToFile (name string , boolChannel chan bool , filePathChannel chan string ) { getwd, _ := os.Getwd() path := getwd + "/" + name + ".txt" filePathChannel <- path close (filePathChannel) file, err := os.Create(path) if err != nil { fmt.Println(err) } defer file.Close() writer := bufio.NewWriter(file) rand.Seed(time.Now().UnixNano()) for i := 0 ; i < 1000 ; i++ { intn := rand.Intn(1000 ) writer.WriteString(strconv.Itoa(intn) + "\n" ) } writer.Flush() boolChannel <- true close (boolChannel) }
4、应用案例—阻塞
1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { intChan := make (chan int , 10 ) exitChan := make (chan bool , 1 ) go writeData(intChan) for _= range exitChan{ fmt.Println("ok..." ) } }
问题:如果注销掉 go readData(intChan, exitChan),程序会怎么样?
答:如果只是向管道写数据,而没有读取,就会出现阻塞而dead lock,原因是intChan容量是10,而代码writeData会写入50个数据,因此会阻塞在writeData
5、应用案例—协程求素数
需求:
要求统计1-200000的数字中,哪些是素数?这个问题在本章开篇就提出了,现在我们有goroutine和channel的知识后,就可以完成了「测试数据:80000」
分析思路:
传统的方法,就是使用一个循环,循环的判断各个数是不是素数「ok」
使用并发/并行的方式,将统计素数的任务分配给多个(4个)goroutine去完成,更快!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 package mainimport ( "fmt" "time" ) func main () { intChan := make (chan int , 1000 ) primeChan := make (chan int , 2000 ) exitChan := make (chan bool , 4 ) go putNum(intChan) for i := 0 ; i < 4 ; i++ { go primeNum(intChan, primeChan, exitChan) } go func () { for i := 0 ; i < 4 ; i++ { <-exitChan } close (primeChan) }() for { res, ok := <-primeChan if !ok { break } fmt.Println(res) } fmt.Println("main线程退出" ) } func putNum (intChan chan int ) { for i := 0 ; i <= 8000 ; i++ { intChan <- i } close (intChan) } func primeNum (intChan chan int , primeChan chan int , exitChan chan bool ) { var flag bool for { time.Sleep(time.Millisecond * 10 ) num, ok := <-intChan if !ok { break } flag = true for i := 2 ; i < num; i++ { if num%i == 0 { flag = false break } } if flag { primeChan <- num } } fmt.Println("有一个primeNum协程因为取不到数据,退出" ) exitChan <- true }
结论:使用go协程后执行速度比普通方法提高至少4倍