GoLang协程Goroutiney原理与GMP模型详解

简介: 【11月更文挑战第4天】Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建和销毁开销小,适合高并发场景。其调度采用非抢占式和协作式多任务处理结合的方式。GMP 模型包括 G(Goroutine)、M(系统线程)和 P(逻辑处理器),通过工作窃取算法实现负载均衡,确保高效利用系统资源。
  1. Goroutine 原理
  • 轻量级线程概念
  • Goroutine 是 Go 语言中并发执行的基本单位,它类似于线程,但比传统的线程更加轻量。在操作系统层面,线程的创建、销毁和切换都有一定的开销。而 Goroutine 是由 Go 运行时(runtime)管理的用户态线程,它的创建和销毁的开销非常小,使得在 Go 程序中可以轻松地创建成千上万个 Goroutine 来实现高并发。
  • 例如,在一个处理网络请求的服务端程序中,可以为每个到来的请求创建一个 Goroutine 来处理,这样可以高效地处理大量并发请求。
  • 调度原理
  • Goroutine 的调度是由 Go 运行时的调度器完成的。当一个 Goroutine 被创建后,它会被放入一个调度队列中等待执行。调度器会根据一定的策略从队列中选取 Goroutine 并将其分配到系统线程(OS Thread)上执行。
  • 与操作系统的线程调度不同,Go 调度器采用了非抢占式多任务处理和协作式多任务处理相结合的方式。在非抢占式调度中,Goroutine 会一直执行,直到它主动让出 CPU 资源,比如通过调用runtime.Gosched()函数。而在某些特殊情况下,如 Goroutine 执行时间过长或者系统调用阻塞时,调度器也会进行抢占式调度,将 CPU 资源分配给其他等待的 Goroutine。
  1. GMP 模型详解
  • G(Goroutine)
  • G 代表 Goroutine,是 Go 程序中实际执行的代码片段。每个 Goroutine 都有自己的栈空间,初始栈大小一般比较小(通常为 2KB),并且可以根据需要动态增长。这与传统线程的固定栈大小相比,更有效地利用了内存资源。
  • 例如,一个简单的 Goroutine 可能是一个函数的执行体,像func() { println("Hello, Goroutine") }这样的函数可以作为一个 Goroutine 来运行。
  • M(Machine,系统线程)
  • M 代表系统线程,是操作系统层面的线程。Go 程序会利用操作系统的线程来执行 Goroutine。M 与内核线程直接相关,它负责执行 Goroutine 中的代码。Go 运行时会根据系统资源和 Goroutine 的数量来动态地创建和销毁 M。
  • 例如,在一个多核 CPU 的系统中,Go 程序可能会创建多个 M 来充分利用多核的优势,每个 M 可以执行一个或多个 Goroutine。
  • P(Processor,逻辑处理器)
  • P 是一个抽象的概念,代表逻辑处理器。它是连接 G 和 M 的桥梁,每个 P 都有一个本地队列(Local Queue),用于存放等待执行的 Goroutine。P 的数量在程序启动时可以通过GOMAXPROCS环境变量或者runtime.GOMAXPROCS()函数来设置,它通常与系统的 CPU 核心数相关,决定了 Go 程序可以同时并发执行的 Goroutine 的数量上限。
  • 例如,假设GOMAXPROCS设置为 4,那么 Go 程序最多可以有 4 个 P,也就意味着最多可以同时有 4 个 Goroutine 在不同的 CPU 核心上执行(不考虑超线程等情况)。
  • GMP 之间的协作关系
  • 当一个 Goroutine 被创建时,它会首先被放入一个 P 的本地队列中。M 会从 P 的本地队列中获取 Goroutine 来执行。如果 P 的本地队列中没有 Goroutine 了,M 会尝试从其他 P 的队列中 “窃取” Goroutine 来执行(工作窃取算法),这样可以保证各个 P 之间的负载均衡。
  • 当 M 因为系统调用等原因阻塞时,它会释放绑定的 P,使得 P 可以与其他 M 绑定继续执行 Goroutine。而当 M 完成系统调用返回后,它会尝试获取一个空闲的 P 或者从其他 P 那里 “窃取” Goroutine 来继续执行。这种机制保证了 Go 程序在面对各种复杂的系统调用和阻塞情况时,仍然能够高效地利用系统资源,保持 Goroutine 的高效调度。
相关文章
|
12天前
|
存储 安全 测试技术
GoLang协程Goroutiney原理与GMP模型详解
本文详细介绍了Go语言中的Goroutine及其背后的GMP模型。Goroutine是Go语言中的一种轻量级线程,由Go运行时管理,支持高效的并发编程。文章讲解了Goroutine的创建、调度、上下文切换和栈管理等核心机制,并通过示例代码展示了如何使用Goroutine。GMP模型(Goroutine、Processor、Machine)是Go运行时调度Goroutine的基础,通过合理的调度策略,实现了高并发和高性能的程序执行。
74 29
|
3天前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
10天前
|
Go 计算机视觉
在Golang高并发环境中如何进行协程同步?
在此示例中,使用互斥锁来保护对共享计数器变量 c 的访问,确保并发的 HTTP 请求不会产生数据竞争。
29 3
|
5月前
|
Go Python
使用python实现一个用户态协程
【6月更文挑战第28天】本文探讨了如何在Python中实现类似Golang中协程(goroutines)和通道(channels)的概念。文章最后提到了`wait_for`函数在处理超时和取消操作中的作
51 1
使用python实现一个用户态协程
|
2月前
|
调度 Python
python3 协程实战(python3经典编程案例)
该文章通过多个实战案例介绍了如何在Python3中使用协程来提高I/O密集型应用的性能,利用asyncio库以及async/await语法来编写高效的异步代码。
20 0
|
4月前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
【7月更文挑战第15天】Python的协程与异步函数优化Web性能,通过非阻塞I/O提升并发处理能力。使用aiohttp库构建异步服务器,示例代码展示如何处理GET请求。异步处理减少资源消耗,提高响应速度和吞吐量,适用于高并发场景。掌握这项技术对提升Web应用性能至关重要。
83 10
|
4月前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
【7月更文挑战第15天】Python 3.5+引入的协程和异步函数革新了并发编程。协程,轻量级线程,由程序控制切换,降低开销。异步函数是协程的高级形式,允许等待异步操作。通过`asyncio`库,如示例所示,能并发执行任务,提高I/O密集型任务效率,实现并发而非并行,优化CPU利用率。理解和掌握这些工具对于构建高效网络应用至关重要。
48 6
|
4月前
|
大数据 数据处理 API
性能飞跃:Python协程与异步函数在数据处理中的高效应用
【7月更文挑战第15天】在大数据时代,Python的协程和异步函数解决了同步编程的性能瓶颈问题。同步编程在处理I/O密集型任务时效率低下,而Python的`asyncio`库支持的异步编程利用协程实现并发,通过`async def`和`await`避免了不必要的等待,提升了CPU利用率。例如,从多个API获取数据,异步方式使用`aiohttp`并发请求,显著提高了效率。掌握异步编程对于高效处理大规模数据至关重要。
52 4
|
4月前
|
设计模式 机器学习/深度学习 测试技术
设计模式转型:从传统同步到Python协程异步编程的实践与思考
【7月更文挑战第15天】探索从同步到Python协程异步编程的转变,异步处理I/O密集型任务提升效率。async/await关键词定义异步函数,asyncio库管理事件循环。面对挑战,如思维转变、错误处理和调试,可通过逐步迁移、学习资源、编写测试和使用辅助库来适应。通过实践和学习,开发者能有效优化性能和响应速度。
51 3
|
4月前
|
调度 Python
揭秘Python并发编程核心:深入理解协程与异步函数的工作原理
【7月更文挑战第15天】Python异步编程借助协程和async/await提升并发性能,减少资源消耗。协程(async def)轻量级、用户态,便于控制。事件循环,如`asyncio.get_event_loop()`,调度任务执行。异步函数内的await关键词用于协程间切换。回调和Future对象简化异步结果处理。理解这些概念能写出高效、易维护的异步代码。
58 2