golang协程goroutine教程

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

前言

项目经常遇到一些批量任务执行太慢,需要开启多线程去处理,记录下在Golang中协程使用的一些操作。


协程介绍

协程是计算机程序的一类组件,推广了协作式多任务的子例程,允许执行被挂起与被恢复。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。协程更适合于用来实现彼此熟悉的程序组件,如协作式多任务、异常处理、事件循环、迭代器、无限列表和管道。

协程与线程的区别在于:

  • 协程的创建和切换开销更小,因此可以创建更多的协程。
  • 协程之间是异步的,也就是说,一个协程的执行不会阻塞另一个协程的执行。
  • 协程的调度是由系统来进行的,程序员不需要手动进行调度。

协程的优势在于:

  • 可以实现高效的并发编程。
  • 可以简化并发编程的代码。
  • 可以提高并发编程的性能。

协程的常见用例包括:

  • 异步网络操作。
  • 异步文件操作。
  • 异步数据库操作。
  • 异步计算。
  • 事件循环。

Golang 语言还提供了 channel 数据结构来用于协程之间的通信。

channel 介绍

在Go语言中,通道(Channel)是一种用于在协程之间进行通信和同步的数据结构。通道提供了一种安全的方式,使一个协程可以向另一个协程发送数据,并保证在接收方准备好之前,发送方会被阻塞。通道是Go语言并发编程的核心机制之一。

以下是关于Golang中通道的一些基本介绍:

  1. 通道的创建:
    使用make函数创建一个通道,通道的类型是数据传递的类型。通道可以是带缓冲的(Buffered Channel)或无缓冲的(Unbuffered Channel)。

    // 无缓冲通道
    ch := make(chan int)
    
    // 带缓冲通道,容量为3
    chBuffered := make(chan int, 3)
    
  2. 通道的发送和接收:
    使用<-运算符进行通道的发送和接收操作。发送和接收操作都是原子的,这有助于避免竞态条件。

    // 发送数据到通道
    ch <- 42
    
    // 从通道接收数据
    value := <-ch
    
  3. 无缓冲通道:
    无缓冲通道在发送和接收数据时,发送方和接收方必须同时准备好,否则它们将阻塞等待。

    ch := make(chan int)
    
    go func() {
        // 发送数据到通道
        ch <- 42
    }()
    
    // 从通道接收数据
    value := <-ch
    
  4. 带缓冲通道:
    带缓冲通道允许在通道满之前缓存一定数量的元素,发送和接收操作变得非阻塞,直到通道满或为空。

    ch := make(chan int, 3)
    
    // 发送数据到通道,不会阻塞
    ch <- 42
    ch <- 43
    ch <- 44
    
  5. 关闭通道:
    使用close函数关闭通道,关闭后的通道不能再发送数据,但可以继续接收已发送的数据。

    close(ch)
    
  6. 通道的选择(select语句):
    select语句用于在多个通道操作中进行选择,以处理多路通信。

    select {
    case msg1 := <-ch1:
        fmt.Println("Received", msg1)
    case msg2 := <-ch2:
        fmt.Println("Received", msg2)
    default:
        fmt.Println("No communication")
    }
    
  7. 通道的方向:
    可以通过在通道类型中指定方向,限制通道的发送或接收操作。

    // 只能发送数据到通道
    func sendData(ch chan<- int) {
        ch <- 42
    }
    
    // 只能从通道接收数据
    func receiveData(ch <-chan int) {
        value := <-ch
    }
    

通道是Go语言中非常强大和灵活的并发原语,能够帮助你构建安全、高效的并发程序。通过良好的通道使用,可以避免共享数据的竞态条件,提高程序的可维护性和稳定性。

基础使用

在Go语言中,协程(Goroutine)是一种轻量级的线程,由Go语言的运行时系统调度。协程使得并发编程更加容易和高效。下面是一些关于Golang协程基础使用的示例:

  1. 创建协程:
    使用关键字 go 可以创建一个新的协程。以下是一个简单的例子:

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        go sayHello()
        time.Sleep(1 * time.Second) // 等待协程执行
    }
    
    func sayHello() {
        fmt.Println("Hello, Goroutine!")
    }
    

    这个例子中,sayHello 函数被放在一个新的协程中运行。

  2. 传递参数给协程:
    如果你需要将参数传递给协程,可以使用闭包。以下是一个例子:

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        msg := "Hello, Goroutine!"
        go func(m string) {
            fmt.Println(m)
        }(msg)
        time.Sleep(1 * time.Second)
    }
    

    在这个例子中,我们创建了一个匿名函数,并在协程启动时传递了 msg 参数。

  3. 等待协程执行完成:
    如果主程序需要等待协程执行完成,可以使用 sync 包或者 channel 来实现。以下是一个使用 sync 包的例子:

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func main() {
        var wg sync.WaitGroup
        wg.Add(1)
    
        go func() {
            defer wg.Done()
            fmt.Println("Hello, Goroutine!")
        }()
    
        wg.Wait()
    }
    

    在这个例子中,sync.WaitGroup 用于等待协程执行完成。

  4. 使用 Channel 进行通信:
    协程之间通过 Channel 进行通信。以下是一个简单的例子:

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        messages := make(chan string)
    
        go func() {
            messages <- "Hello, Goroutine!"
        }()
    
        msg := <-messages
        fmt.Println(msg)
    }
    

    这个例子中,messages 是一个字符串类型的 channel,协程通过 <- 运算符发送消息,主程序通过 <- 运算符接收消息。

这些是一些基础的 Golang 协程使用的例子。在实际开发中,协程的使用可以更加复杂,涉及到协程之间的同步、错误处理等方面的考虑。

协程中传参数示例

下面是一个示例,其中一个协程负责执行任务,接收参数,返回结果,而主程序等待协程完成并获取结果:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	resultCh := make(chan int, 1)

	wg.Add(1)
	go worker(5, &wg, resultCh)

	wg.Wait()

	// 从通道中获取结果
	result := <-resultCh
	fmt.Println("Result:", result)
}

func worker(value int, wg *sync.WaitGroup, resultCh chan int) {
	defer wg.Done()

	// 模拟一些工作
	result := value * 2

	// 将结果发送到通道
	resultCh <- result
}

在这个示例中,worker 函数是一个协程,负责执行任务。它接收一个整数参数 value,执行一些工作(这里简单地将参数乘以2),然后将结果发送到结果通道 resultCh

主程序创建了一个 sync.WaitGroup 用于等待协程完成,还创建了一个通道 resultCh 用于接收结果。主程序启动了一个协程并传递了参数5给 worker 函数。然后,主程序使用 Wait 方法等待协程完成。

在协程执行完成后,它会将结果发送到通道,并主程序通过 <-resultCh 语句从通道中获取结果。最后,主程序打印出获取的结果。

这个例子演示了如何在协程中执行任务,传递参数,获取结果,并等待协程完成。

协程中channel和select使用

下面是一个带有管道和 select 的复杂示例。在这个示例中,有两个协程,一个生成随机数并将其发送到管道,另一个协程从管道接收随机数并执行不同的任务。主程序使用 select 语句等待这两个协程的完成:

package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

func main() {
	randCh := make(chan int)
	resultCh := make(chan int)

	var wg sync.WaitGroup
	wg.Add(2)

	go randomNumberGenerator(randCh, &wg)
	go processNumbers(randCh, resultCh, &wg)

	go func() {
		wg.Wait()
		close(resultCh)
	}()

	// 使用 select 语句等待协程完成
	for {
		select {
		case num, ok := <-resultCh:
			if !ok {
				fmt.Println("All tasks completed.")
				return
			}
			fmt.Println("Processed number:", num)
		case <-time.After(2 * time.Second):
			fmt.Println("Timeout: No result received in 2 seconds.")
			return
		}
	}
}

func randomNumberGenerator(randCh chan int, wg *sync.WaitGroup) {
	defer wg.Done()
	rand.Seed(time.Now().UnixNano())

	for i := 0; i < 5; i++ {
		randomNum := rand.Intn(100)
		fmt.Println("Generated random number:", randomNum)
		randCh <- randomNum
		time.Sleep(500 * time.Millisecond)
	}

	close(randCh)
}

func processNumbers(randCh chan int, resultCh chan int, wg *sync.WaitGroup) {
	defer wg.Done()

	for {
		select {
		case num, ok := <-randCh:
			if !ok {
				fmt.Println("Number generator closed.")
				return
			}
			// 模拟处理任务
			result := num * 2
			resultCh <- result
		}
	}
}

在这个示例中,randomNumberGenerator 协程生成随机数并将其发送到 randCh 管道。processNumbers 协程从 randCh 管道接收随机数,并执行一些任务,将结果发送到 resultCh 管道。

主程序使用 select 语句等待 resultCh 管道中的结果,同时设置一个 2 秒的超时。如果在超时之前没有接收到结果,主程序会输出超时消息。这个例子演示了如何使用管道和 select 来协调和同步不同的协程。文章来源地址https://www.toymoban.com/news/detail-783505.html

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

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

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

相关文章

  • Go学习第十一章——协程goroutine与管道channel

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

    2024年02月08日
    浏览(40)
  • golang学习-goroutine

    1、goroutine协程 goroutine 是 Go 语言支持并发的核心,一个goroutine会以一个很小的栈开始其生命周期,一般只需要2KB。区别于操作系统线程由系统内核进行调度, goroutine 是由Go运行时(runtime)负责调度。例如Go运行时会智能地将 m个goroutine 合理地分配给n个操作系统线程,实现类

    2024年01月18日
    浏览(42)
  • golang Goroutine超时控制

     https://github.com/zeromicro/go-zero/blob/master/core/fx/timeout.go  一文搞懂 Go 超时控制_51CTO博客_go 超时处理

    2024年02月09日
    浏览(43)
  • Golang开发--Goroutine的使用

    Go 语言天生支持并发编程,提供了丰富的原语和工具来编写并发程序。Goroutine 是 Go 语言中的轻量级执行单位。它们是由 Go 运行时(runtime)管理的,并且能够在单个线程上运行成千上万个 Goroutine。创建 Goroutine 非常高效,可以通过使用 go 启动一个新的 Goroutine。例如,

    2024年02月09日
    浏览(44)
  • Golang goroutine MPG 模式浅析

    快速入门小结: (1) 主线程是一个物理线程,直接作用在cpu上的 。是重量级的,非常耗费cpu资源。 (2)协程从主线程开局的,是轻量级的线程,是逻辑态,对资源消耗相对小。 (3)Golang的协程机制是重要的特点,可以轻松的开启上万个协程。其它编程语言的并发机制是

    2024年02月08日
    浏览(50)
  • Golang 中goroutine、channel 生产环境中例子和应用

    Golang 学习生产环境中例子和应用 大家好,今天我们来聊一聊goroutine、channel产品开发中的应用。如果你还不知道这些是什么,那么恭喜你,你来对地方了!因为我也不知道。 好了,开玩笑了。其实这些都是Go语言中非常重要的概念,尤其是在并发编程中。那么我们来看一下,

    2024年02月10日
    浏览(56)
  • Golang中的管道(channel) 、goroutine与channel实现并发、单向管道、select多路复用以及goroutine panic处理

    目录 管道(channel) 无缓冲管道 有缓冲管道 需要注意 goroutine与channel实现并发 单向管道 定义单向管道 将双向管道转换为单向管道 单向管道作为函数参数 单向管道的代码示例 select多路复用 案例演示 goroutine panic处理 案例演示 管道(channel)是 Go 语言中实现并发的一种方式,

    2024年02月06日
    浏览(47)
  • Golang单元测试与Goroutine详解 | 并发、MPG模式及CPU利用

    深入探讨Golang中单元测试方法及Goroutine的使用。了解并发与并行概念,MPG模式以及CPU相关函数的应用。解决协程并行中的资源竞争问题。

    2024年02月10日
    浏览(45)
  • Python多任务教程:进程、线程、协程

    进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程是一种抽象的概念,从来没有统一的标准定义。进程一般由程序、数据集合和进程控制块三部分组成。程序用于描述进

    2024年02月12日
    浏览(41)
  • Golang协程,通道详解

    进程 (Process)就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位,进程是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进程都有一个自己的地址空间。 一个进程至少有 5 种基本状态,它们是:初始态,执行态,等待状

    2024年02月12日
    浏览(36)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包