ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Golang-协程、管道和文件操作综合练习题

2021-12-15 10:34:33  阅读:210  来源: 互联网

标签:练习题 10 协程 int lock chan Golang str


协程、管道和文件操作综合练习题

案例一:

要求:
//1.启动一个协程,将1-2000的数字放到channel(numChan)中
// 2.启动8个协程,从numChan取出数(n),并计算1+…+n的值,存放到resChan
// 3.最后8个协程协同完成工作后,再遍历resChan,显示结果如res[1]=1…res[10]=55
// 4.注意考虑resChan chan int是否合适?
代码:

package main

import (
	"fmt"
	"sync"
)

// 要求:1.启动一个协程,将1-2000的数字放到channel(numChan)中
// 2.启动8个协程,从numChan取出数(n),并计算1+..+n的值,存放到resChan
// 3.最后8个协程协同完成工作后,再遍历resChan,显示结果如res[1]=1...res[10]=55
// 4.注意考虑resChan chan int是否合适?

var (
	n1      int  = 0
	account *int = &n1
	lock    sync.Mutex
)

func addUpper(n int, c1 chan map[int]int) {
	resMap := make(map[int]int, 1)
	res := 0
	for i := 1; i <= n; i++ {
		res += i
	}
	resMap[n] = res
	c1 <- resMap
	lock.Lock()
	// 方法一
	// if n == cap(c1) {
	// 	close(c1)
	// }
	// 方法二
	// 使用全局变量*account记录addUpper()运行次数,
	// 为防止资源冲突,使用全局变量互斥锁
	*account++
	if *account == cap(c1) {
		close(c1)
	}
	lock.Unlock()
}

func readData(c2 chan map[int]int, c3 chan bool) {
	for {
		v, ok := <-c2
		if !ok {
			break
		}
		fmt.Println("v=", v)
	}
	c3 <- true
	close(c3)

}

func main() {
	numchan := make(chan int, 2000)
	// 1.
	go func(c chan int) {
		for i := 1; i <= 2000; i++ {
			c <- i
		}
		close(c)
	}(numchan)

	// 2.
	resChan := make(chan map[int]int, 2000)
	for i := 0; i < 8; i++ {
		for v := range numchan {
			go addUpper(v, resChan)
		}
	}

	// 3.

	exitChan := make(chan bool, 1)
	go readData(resChan, exitChan)
	for {
		if _, ok := <-exitChan; ok {
			break
		}
	}
	fmt.Println("读写操作完成")
}

案例二:

// 1)开一个协程 writeDataToFile,随机生成1000个数据,存放到文件
// 2)当writeDataFile 完成写入操作后,让sort协程从文件中读取1000个数据,
// 并完成排序,重新写入到另一个文件
// 3)考察点,协程+管道+文件的综合使用
// 4)功能扩展:开10个协程writeDataFile,每个协程随机生成1000个数据,存放放到10个文件中
// 5)当10个文件都生成了,让10个sort协程从10个文件中读取1000个数据,并完成排序,
// 并重新写入到10个新文件中

先完成前三个要求的代码:

package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"
)

// 要求:1)开一个协程 writeDataToFile,随机生成1000个数据,存放到文件
// 2)当writeDataFile 完成写入操作后,让sort协程从文件中读取1000个数据,
// 并完成排序,重新写入到另一个文件
// 3)考察点,协程+管道+文件的综合使用

// var lock sync.Mutex
func writeDataFile(c1 chan int, c2 chan bool) {
	for i := 1; i <= 1000; i++ {
		c1 <- rand.Intn(1000) + 1
	}
	close(c1)
	filePath := "E:\\goproject\\src\\go_code\\chapter15\\homework\\case2\\write文件.txt"
	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	for {
		v, ok := <-c1
		if !ok {
			break
		}
		str := strconv.Itoa(v) + "\n"
		writer.WriteString(str)
	}
	writer.Flush()
	c2 <- true
	close(c2)

}

func sortData(c1 chan int, c2 chan bool) {
	intSlice := make([]int, 0)
	file, err := os.Open("E:\\goproject\\src\\go_code\\chapter15\\homework\\case2_1\\write文件.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	reader := bufio.NewReader(file)

	for {
		str, err1 := reader.ReadString('\n')
		if err1 != nil {
			if err1 == io.EOF {
				break
			}
			log.Fatal(err1)
		}
		// 提取出的str字符串含有'\n',需要去除
		// 采用strings.Trim(s string,cutset string)string
		new_str := strings.Trim(str, "\n")
		//将字符串转化为int 类型
		// lock.Lock()
		a, _ := strconv.ParseInt(new_str, 10, 64)
		intSlice = append(intSlice, int(a))
		// lock.Unlock()
	}
	sort.Ints(intSlice)

	// 将排序好后的数据写入管道
	for _, v := range intSlice {
		c1 <- v
	}
	close(c1)

	// 把管道中的数据写入新文件
	filePath := "E:\\goproject\\src\\go_code\\chapter15\\homework\\case2_1\\sort文件.txt"
	file1, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
	if err != nil {
		log.Fatal(err)
	}
	defer file1.Close()

	writer := bufio.NewWriter(file1)

	for {
		v, ok := <-c1
		if !ok {
			break
		}
		str := strconv.Itoa(v) + "\n"
		writer.WriteString(str)
		// fmt.Println(str)
	}
	writer.Flush()
	c2 <- true
	close(c2)
}

func main() {
	rand.Seed(time.Now().UnixNano())
	intChan1 := make(chan int, 1000)
	exitChan1 := make(chan bool, 1)
	intChan2 := make(chan int, 10000)
	exitChan2 := make(chan bool, 1)
	go writeDataFile(intChan1, exitChan1)
	for {
		if _, ok := <-exitChan1; ok {
			break
		}
	}

	go sortData(intChan2, exitChan2)
	for {
		if _, ok := <-exitChan2; ok {
			break
		}
	}
	fmt.Println("test...")

}

扩展功能后的代码:

package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

// 4)功能扩展:开10个协程writeDataFile,每个协程随机生成1000个数据,存放放到10个文件中
// 5)当10个文件都生成了,让10个sort协程从10个文件中读取1000个数据,并完成排序,
// 并重新写入到10个新文件中

var (
	n1      int  = 0
	account *int = &n1
	n2      int  = 0
	p       *int = &n2
	lock    sync.Mutex
)

func writeDataFile(j int, c1 chan int, c2 chan bool) {
	// 每开辟一个协程,向管道中添加1000个随机数
	for i := 1; i <= 1000; i++ {
		c1 <- rand.Intn(1000) + 1
	}

	// 没开辟一个协程,建立一个新文件
	filePath := "E:\\goproject\\src\\go_code\\chapter15\\homework\\case2_2\\write文件" + strconv.Itoa(j+1) + ".txt"
	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	// 建立带缓存的writer
	writer := bufio.NewWriter(file)
	// 每个文件写入1000个数据
	for i := 1; i <= 1000; i++ {
		v, ok := <-c1
		if !ok {
			break
		}
		str := strconv.Itoa(v) + "\n"
		writer.WriteString(str)
	}
	writer.Flush()

	// 使用全局变量 *int类型 记录写入次数,当写入10次后,关闭管道
	// 在通过退出标识管道 推入true ,让主程序结束阻塞
	lock.Lock()
	*account++
	if *account == 10 {
		close(c1)

		if _, ok := <-c1; !ok {
			c2 <- true
			close(c2)
		}
	}
	lock.Unlock()

}

func sortData(j int, c1 chan int, c2 chan bool) {
	intSlice := make([]int, 0)
	file, err := os.Open("E:\\goproject\\src\\go_code\\chapter15\\homework\\case2_2\\write文件" + strconv.Itoa(j+1) + ".txt")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	reader := bufio.NewReader(file)

	for {
		str, err1 := reader.ReadString('\n')
		if err1 != nil {
			if err1 == io.EOF {
				break
			}
			log.Fatal(err1)
		}
		// 提取出的str字符串含有'\n',需要去除
		// 采用strings.Trim(s string,cutset string)string
		new_str := strings.Trim(str, "\n")
		//将字符串转化为int 类型
		// lock.Lock()
		a, _ := strconv.ParseInt(new_str, 10, 64)
		intSlice = append(intSlice, int(a))
		// lock.Unlock()
	}
	sort.Ints(intSlice)

	// 将排序好后的数据写入管道
	// 出现问题:多个协程同时往管道写入内容,数据的顺序排序输入变得无意义
	// 需要一个实现一个协程工作完后,管道才接受下一个协程的操作
	//解决方方法使用了全局变量*P作为1000次写入的判断基准,为防止资源冲突
	// 使用了全局变量互斥锁
	for {
		lock.Lock()
		a := *p
		lock.Unlock()
		if a == 1000*j {
			lock.Lock()
			for _, v := range intSlice {
				c1 <- v
				*p++
			}

			// 把管道中的数据写入新文件
			filePath := "E:\\goproject\\src\\go_code\\chapter15\\homework\\case2_2\\sort文件" + strconv.Itoa(j+1) + ".txt"
			file1, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
			if err != nil {
				log.Fatal(err)
			}
			defer file1.Close()

			writer := bufio.NewWriter(file1)

			for i := 1; i <= 1000; i++ {
				v, ok := <-c1
				if !ok {
					break
				}
				str := strconv.Itoa(v) + "\n"
				writer.WriteString(str)
				// fmt.Println(str)
			}
			writer.Flush()

			lock.Unlock()
			break
		}
		// lock.Unlock()
	}

	// 使用全局变量 *int类型 记录写入次数,当写入10次后,关闭管道
	// 在通过退出标识管道 推入true ,让主程序结束阻塞
	lock.Lock()
	*account++
	if *account == 20 {
		close(c1)

		if _, ok := <-c1; !ok {
			c2 <- true
			close(c2)
		}
	}
	lock.Unlock()
}

func main() {
	rand.Seed(time.Now().UnixNano())
	intChan1 := make(chan int, 10000)
	exitChan1 := make(chan bool, 1)
	intChan2 := make(chan int, 10000)
	exitChan2 := make(chan bool, 1)
	for i := 0; i < 10; i++ {
		go writeDataFile(i, intChan1, exitChan1)
	}
	for {
		if _, ok := <-exitChan1; ok {
			break
		}
	}

	for i := 0; i < 10; i++ {
		go sortData(i, intChan2, exitChan2)
	}
	for {
		if _, ok := <-exitChan2; ok {
			break
		}
	}
	fmt.Println("test...")
}

标签:练习题,10,协程,int,lock,chan,Golang,str
来源: https://blog.csdn.net/ALEX_CYL/article/details/121946287

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有