go的协程和管道运用案例

这篇具有很好参考价值的文章主要介绍了go的协程和管道运用案例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.同时向管道读写数据

package main

import "fmt"

func main() {
    writeChan := make(chan int, 20)   // 写入通道,缓冲大小为20
    exitChan := make(chan bool)   // 退出通道

    go readData(writeChan, exitChan)   // 启动readData协程
    go writeData(writeChan)   // 启动writeData协程

    for {
        v, ok := <-exitChan   // 接收退出通道值
        if ok {
            fmt.Println("完成:", v)   // 打印完成信息
            break   // 退出循环
        }
    }
}

func writeData(writeChan chan int) {
    for i := 1; i <= 20; i++ {
        writeChan <- i   // 将i写入通道
        fmt.Println("写入数据~~:", i)   // 打印写入数据信息
    }
    close(writeChan)   // 关闭通道
}

func readData(writeChan chan int, exitChan chan bool) {
    for v := range writeChan {
        fmt.Println("读取数据~~:", v)   // 打印读取数据信息
    }
    // 结束
    exitChan <- true   // 向退出通道发送完成信号
    close(exitChan)   // 关闭通道
}

二.协程案例-计算2000个数各个数的累加和

package main

import (
	"fmt"
	"sync"
)

var (
	wg3 sync.WaitGroup // wg3用于等待PutData函数执行完成
	wg4 sync.WaitGroup // wg4用于等待SumUp函数执行完成
)

func main() {
	numChan := make(chan int, 2000) // 创建一个缓冲大小为2000的整型通道
	wg3.Add(2000) // 将等待计数器设置为2000
	go PutData(numChan) // 启动PutData协程,向numChan通道写入数据
	wg3.Wait() // 等待PutData协程执行完成
	close(numChan) // 关闭numChan通道
	fmt.Println("num:", len(numChan)) // 打印numChan通道内的数据个数(应为2000)
	wg4.Add(2000) // 将等待计数器设置为2000
	resChan := make(chan map[int]int, 2000) // 创建一个缓冲大小为2000的映射整型到映射整型的通道
	for n := range numChan {
		go SumUp(n, resChan) // 启动SumUp协程,计算numChan中的每个数字的累加和并存储到resChan通道
	}
	wg4.Wait() // 等待所有SumUp协程执行完成
	close(resChan) // 关闭resChan通道
	fmt.Println("res:", len(resChan)) // 打印resChan通道内的数据个数(应为2000)
	for res := range resChan {
		for key, val := range res {
			fmt.Printf("res[%v]=%v\n", key, val) // 遍历输出resChan通道中的结果
		}
	}
}

// SumUp 计算累加和
func SumUp(n int, resChan chan map[int]int) {
	sumMap := make(map[int]int) // 创建一个整型到整型的映射
	res := 0 // 初始化res为0
	for i := 1; i <= n; i++ {
		res += i // 将i累加到res上
	}
	sumMap[n] = res // 将res存储到sumMap中对应的n位置
	resChan <- sumMap // 将sumMap发送到resChan通道
	defer wg4.Done() // 在协程结束时,将等待计数器减1
}

func PutData(numChan chan int) {
	for i := 1; i <= 2000; i++ {
		numChan <- i // 将i发送到numChan通道
		wg3.Done() // 等待发送完成后,将等待计数器减1
	}
}

三.生产1000个数据保存文件,读取文件排序后另存文件

package main

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

var (
    wg5 sync.WaitGroup // wg5用于等待所有goroutine完成
)

// goroutine+channel实现写入文件和排序
func main() {
    wg5.Add(1000)        // 增加1000个等待的goroutine
    go writeDataToFile() // 启动写入数据到文件的goroutine
    wg5.Wait()           // 等待所有goroutine完成
    fmt.Println("文件写入完成!!!!!!!!!!")
    fmt.Println()

    fmt.Println("读取所写文件对其排序生成新的文件!!!!!!!")
    dataChan := make(chan int, 1000) // 创建一个容量为1000的整型通道
    readDataToChannel(dataChan)      // 启动读取数据到通道的goroutine
    sortToSave(dataChan)             // 对通道中的数据进行排序和保存
}

// 将数据放入切片 对切片排序 再写入文件保存
func sortToSave(dataChan chan int) {
    dataSlice := make([]int, len(dataChan)) // 创建一个与通道长度相同的切片
    for i := 0; i < len(dataSlice); i++ {
       for data := range dataChan { // 从通道中接收数据
          dataSlice[i] = data
          break
       }
    }
    fmt.Println(len(dataSlice)) // 打印切片长度, 为1000
    QuickSort(dataSlice)        // 使用快速排序
    fmt.Println("排序后:", dataSlice)

    file, err := os.OpenFile("d:/go-test/sortData.txt", os.O_WRONLY|os.O_TRUNC|os.O_APPEND|os.O_CREATE, 0666) // 打开或创建文件
    if err != nil {
       fmt.Println("open file err ", err)
       return
    }
    defer file.Close()              // 函数返回前关闭文件
    writer := bufio.NewWriter(file) // 创建写入器

    for i := 0; i < len(dataSlice); i++ {
       _, err := writer.WriteString(strconv.Itoa(dataSlice[i]) + ",") // 将切片中的数据写入文件
       if err != nil {
          fmt.Println("write file err ", err)
          break
       }
    }
    writer.Flush() // 刷新写入器
    fmt.Println("有序文件写入完成!!!!!")
}

// 随机生产1000个数据写入文件
func writeDataToFile() {
    rand.Seed(time.Now().UnixNano())                                                                      // 使用当前时间作为随机数种子
    file, err := os.OpenFile("d:/go-test/data.txt", os.O_WRONLY|os.O_TRUNC|os.O_APPEND|os.O_CREATE, 0666) // 打开或创建文件
    if err != nil {
       fmt.Println("open file err ", err)
       return
    }
    defer file.Close() // 函数返回前关闭文件

    writer := bufio.NewWriter(file) // 创建写入器

    for i := 0; i < 1000; i++ {
       _, err := writer.WriteString(strconv.Itoa(rand.Intn(1000)+1) + ",") // 随机生成1000个数据并写入文件
       wg5.Done()                                                          // wg5计数减1
       if err != nil {
          fmt.Println("write file err ", err)
          break
       }
    }
    writer.Flush() // 刷新写入器
}

// 从文件中读取数据到通道
func readDataToChannel(dataChan chan int) {
    file, err := os.Open("d:/go-test/data.txt") // 打开文件
    if err != nil {
       fmt.Println("open file err ", err)
       return
    }
    defer file.Close()              // 函数返回前关闭文件
    reader := bufio.NewReader(file) // 创建读取器

    for {
       dataStr, errRead := reader.ReadString(',') // 从文件中读取数据直到文件末尾或发生错误
       if errRead != nil {
          if errRead == io.EOF {
             fmt.Println("读取结束!!!!")
          } else {
             fmt.Println("读取错误:", errRead)
          }
          break
       }
       atoi, _ := strconv.Atoi(strings.Trim(dataStr, ",")) // 将字符串转换为整数
       dataChan <- atoi                                    // 将整数发送到通道
    }

    close(dataChan)                   // 在写入所有数据后关闭通道
    fmt.Println("长度:", len(dataChan)) // 打印通道长度, 为1000
}

// QuickSort 快速排序
func QuickSort(arr []int) {
    // 结束条件
    if len(arr) < 2 {
       return
    }
    left, right := 0, len(arr)-1 // 定义分区点的左右指针
    pivot := right               // 将分区点设置为数组的最后一个元素

    for i := 0; i < len(arr); i++ {
       if arr[i] < arr[pivot] {
          arr[left], arr[i] = arr[i], arr[left] // 将较小的元素交换到左边
          left++
       }
    }

    arr[left], arr[right] = arr[right], arr[left] // 将分区点交换到中间
    QuickSort(arr[:left])                         // 对分区点左边的子数组进行递归排序
    QuickSort(arr[left+1:])                       // 对分区点右边的子数组进行递归排序
}

文章来源地址https://www.toymoban.com/news/detail-806137.html

到了这里,关于go的协程和管道运用案例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go语言中,如何做到数据按类别分发给特定的协程处理

    在 Go 语言中,如果你想按类别将数据分配给特定的协程(goroutine)进行处理,可以使用几种策略。下面我将提供一些方法和示例,说明如何根据数据类别将任务分配给不同的协程来处理。 使用通道(Channel)分发数据 使用映射函数和协程池 使用单一分发器(Dispatcher) 方法

    2024年04月28日
    浏览(13)
  • Go学习第十一章——协程goroutine与管道channel

    1 协程goroutine 1.1 基本介绍 前置知识:“进程和线程”,“并发与并行” 协程的概念 协程(Coroutine)是一种用户态的轻量级线程,不同于操作系统线程,协程能够在单个线程中实现多任务并发,使用更少的系统资源。协程的运行由程序控制,不需要操作系统介入,因此协程之

    2024年02月08日
    浏览(23)
  • Go语言-无限可能的管道协程:解锁并发编程的新境界

    在Go语言中,协程(Goroutine)是一种轻量级的并发执行单位,它可以与其他协程并发执行,但不同于操作系统级别的线程。Go语言的协程由Go运行时(Go runtime)来调度,可以在相同的地址空间中并发执行,并且具有非常小的切换开销。 以下是一些关于Go协程的重要特点和用法:

    2024年01月24日
    浏览(25)
  • Linux的进程,协程和线程

    Linux的进程、协程和线程是计算机科学中重要的概念,它们在操作系统和并发编程中发挥着关键的作用。让我们逐个详解这些概念,并讨论它们之间的关系。 进程是操作系统中的一个执行单元,它包含了程序执行所需的所有资源,如内存空间、文件描述符、寄存器等。 进程是

    2024年01月23日
    浏览(21)
  • 多线程、协程和多进程并发编程

    37.1 如何通俗理解线程和进程? 进程:进程就是正在执⾏的程序。 线程:是程序执⾏的⼀条路径, ⼀个进程中可以包含多条线程。 通俗理解:例如你打开抖⾳,就是打开⼀个进程,在抖⾳⾥⾯和朋友聊天就是开启了⼀条线程。 再举⼀个例⼦: 在某⻝堂打饭的时候,此⻝堂安

    2024年02月02日
    浏览(75)
  • Unity中的协程

    定义: 协程使得任务的执行可以分配到多个帧中完成,在Unity中,协程从开始执行到第一个yield return 语句后将调用权归还Unity主线程,并在紧随的下一帧继续从上次结束调用的代码上下文位置恢复执行。 常见应用场景: HTTP请求、资源加载和文件I/O等长时间的异步操作等。

    2024年01月20日
    浏览(17)
  • unity 等待事件之协程和Invoke

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 协程的用法 和 Invoke 的等待事件使用 提示:以下是本篇文章正文内容,下面案例可供参考 代码如下(示例): 好记性不如烂笔头!

    2024年04月13日
    浏览(15)
  • Unity 的协程的原理

    Unity是一款非常强大的游戏引擎,它支持多种编程语言,其中最常用的语言是C#。在Unity中,协程是一种非常强大的功能,它可以让我们在游戏中实现各种各样的效果。本文将详细介绍Unity协程的原理,并给出示例代码详解。 对啦!这里有个游戏开发交流小组里面聚集了一帮热

    2024年02月02日
    浏览(24)
  • Python、Rust中的协程

    协程在不同的堆栈上同时运行,但每次只有一个协程运行,而其调用者则等待: F启动G,但G并不会立即运行,F必须显式的恢复G,然后 G 开始运行。 在任何时候,G 都可能转身并让步返回到 F。这会暂停 G 并继续 F 的恢复操作。 F再次调用resume,这会暂停F并继续G的yield。它们不

    2024年02月09日
    浏览(17)
  • 浅谈Lua协程和函数的尾调用

    虽然不经常用到协程,但是也不能谈虎色变。同时,在有些场景,协程会起到一种不可比拟的作用。所以,了解它,对于一些功能,也会有独特的思路和想法。 概念 关于进程和线程的概念就不多说。 那么从多线程的角度来看,协程和线程有点类似:拥有自己的栈,局部变量

    2024年02月10日
    浏览(20)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包