• Golang入门:协程(goroutine)


    goroutine

    goroutine是Go的并发模型的核心概念。为了理解goroutine,我们来定义几个术语。第一个是进程。进程是程序的实例,由计算机的操作系统运行。操作系统将一些资源(如内存)与进程相关联,并确保其他进程不能访问它们。进程由一个或多个线程组成一个线程是一个执行单元,由操作系统运行。一个进程中的线程共享对资源的访问。一个CPU可以同时执行多少个线程的指令取决于内核的数量。操作系统的工作之一是在CPU上调度线程,以确保每个进程(以及进程中的每个线程)都有机会运行。

    goroutine是由Go运行时管理的轻量级进程。当Go程序启动时,Go运行时会创建一些线程并启动一个goroutine来运行程序。你的程序创建的所有goroutine(包括程序入口部分)都由Go运行时调度器自动分配给这些线程,就像操作系统在CPU内核间调度线程一样。这似乎看起来是额外的工作,因为底层操作系统已经包含了一个管理线程和进程的调度器,但goroutine有几个好处:

    1. 创建goroutine比创建线程更快,因为你不是在创建操作系统级的资源。2. goroutine的初始栈比线程栈更小,并且可以根据需要增长。这使得goroutine的内存效率更高。3. 在goroutine之间切换比在线程之间切换更快,因为goroutine之间的切换完全发生在进程内部,避免了操作系统(相对)缓慢的调用。4. 调度器作为Go进程的一部分能够进行优化。当调度器与网络轮询器一起工作时,可以检测goroutine何时因为I/O阻塞而无法调度。它还与垃圾回收器集成,确保工作在所有操作系统线程之间可以较为平均地分配给Go进程。

    这些优势使得Go程序可以同时生成数百、数千甚至数万个goroutine。如果你尝试在一种使用本地线程的语言中启动成千上万个线程,程序就会慢到如同乌龟在爬行。

    如果你有兴趣了解关于调度器的更多知识,可以听一下Kavya Joshi在GopherCon 2018上发表的名为“The Scheduler Saga”的演讲(https://oreil.ly/879mk)。

    在一个函数调用前放置go关键字可以启动一个goroutine。与其他函数一样,我们可以向它传递参数以初始化其状态。不过,任何函数返回的值都会被忽略。

    任何函数都可以作为goroutine启动。这与JavaScript不同,在JavaScript中,只有当使用async关键字声明函数时,函数才会异步运行。然而,在Go中,大家习惯于用一个封装业务逻辑的闭包来启动goroutine。该闭包负责管理并发的数据和状态。例如,闭包从通道中读取数值并将其传递给业务逻辑,业务逻辑完全不知道它是在一个goroutine中运行的。然后,函数的结果被写回另一个通道。这种职责分离使代码模块化、可测试,并使API调用简单,无须关注并发问题:

    1. func process(val int) int {
    2. // do something with val
    3. }
    4. func runTingConcurrently(in <-chan int, out chan<- int) {
    5. go func() {
    6. for val := range in {
    7. result := process(val)
    8. out <- result
    9. }
    10. }()
    11. }
  • 相关阅读:
    Oracle基础语法
    五. 激光雷达建图和定位方案-引言
    C++基本知识(二)---函数重载、引用、内联函数、auto关键字
    基于JAVASketch2Mod网站计算机毕业设计源码+系统+lw文档+部署
    Mysql批量插入数据时如何解决重复问题
    操作教程|如何注册成为Moonbeam社区代表参与治理
    QT中拷贝一个项目的ui界面到另一个项目时Ui.h文件时Ui.h文件控件变量错乱问题解决
    嵌入式软件找实习需要掌握哪些知识?
    Spring IoC和DI的理解
    基于RAM实现乒乓buffer
  • 原文地址:https://blog.csdn.net/Guzarish/article/details/125633316