[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-12":3},{"id":4,"title":5,"title_en":6,"abstract":7,"abstract_en":6,"content":8,"content_en":9,"category":10,"banner_id":11,"banner_path":12,"tags":13,"is_recommend":15,"prev_article":16,"next_article":20,"created_at":24},12,"深入了解 Go 语言协程","Deep Dive into Go Language Goroutines","# 深入了解 Go 语言协程\n\n![go](https:\u002F\u002Fwallpapercave.com\u002Fwp\u002Fwp7041189.jpg)\n\n\n在当今的软件开发领域，并发编程已成为提升程序性能和响应能力的关键","# 深入了解 Go 语言协程\n\n![go](https:\u002F\u002Fwallpapercave.com\u002Fwp\u002Fwp7041189.jpg)\n\n\n在当今的软件开发领域，并发编程已成为提升程序性能和响应能力的关键技术。而在 Go 语言中，协程（Goroutine）作为一种轻量级的并发执行单元，凭借其高效、简洁的特性，成为了 Go 语言并发编程的核心优势。\n\n## 协程的基本概念\n\n协程是 Go 语言特有的一种用户态线程，它由 Go 运行时（Runtime）负责管理，而非操作系统内核。与传统的操作系统线程相比，协程的创建和销毁成本极低，所需的内存资源也非常少，通常一个协程只需要几 KB 的栈空间，而且栈还能根据需要动态地扩大和缩小。这使得在一个 Go 程序中可以轻松创建成千上万甚至上百万个协程，而不会给系统带来过大的负担。\n\n## 协程与进程、线程的区别\n\n\n\n*   **进程**：进程是操作系统进行资源分配和调度的基本单位，每个进程都拥有独立的内存空间和系统资源。进程之间的切换需要消耗大量的系统资源，因为涉及到内存上下文的保存和恢复等操作。\n\n*   **线程**：线程是进程内的一个执行单元，一个进程可以包含多个线程，这些线程共享进程的内存空间和系统资源。线程的切换成本虽然比进程低，但仍然需要操作系统内核进行调度，存在一定的开销。\n\n*   **协程**：协程运行在用户态，其调度完全由 Go 运行时控制，不需要操作系统内核的参与。协程之间的切换只需要保存和恢复少量的寄存器状态，开销极小。而且多个协程可以运行在同一个操作系统线程上，通过 Go 运行时的调度器实现并发执行。\n\n## 协程的创建与启动\n\n在 Go 语言中，创建和启动一个协程非常简单，只需要在函数或方法调用前加上关键字`go`即可。例如：\n\n\n\n```\npackage main\n\nimport \"fmt\"\n\nfunc sayHello() {\n\n    fmt.Println(\"Hello, Goroutine!\")\n\n}\n\nfunc main() {\n\n    go sayHello() \u002F\u002F 启动一个协程执行sayHello函数\n\n    \u002F\u002F 主函数等待一段时间，确保协程有机会执行\n\n    time.Sleep(time.Second)\n\n}\n```\n\n在上面的代码中，`go sayHello()`语句启动了一个新的协程来执行`sayHello`函数。需要注意的是，主函数（main 函数）所在的协程是程序的入口，如果主协程执行完毕，程序就会退出，不管其他协程是否执行完毕。所以在示例中，使用`time.Sleep`函数让主协程等待一段时间，以保证新启动的协程能够执行。\n\n## 协程间的通信\n\n多个协程之间需要进行通信和同步，以协同完成任务。Go 语言提供了通道（Channel）机制来实现协程间的安全通信。通道就像一个管道，协程可以通过它发送和接收数据，并且通道保证了数据的同步性，避免了多个协程同时访问共享资源而导致的竞态条件问题。\n\n创建一个通道可以使用`make`函数，指定通道中元素的类型。例如：\n\n\n\n```\nch := make(chan int) \u002F\u002F 创建一个可以传递int类型数据的通道\n```\n\n协程可以通过`&lt;-`操作符向通道发送数据或从通道接收数据。发送数据的语法是`ch &lt;- 数据`，接收数据的语法是`变量 &lt;- ch`。例如：\n\n\n\n```\npackage main\n\nimport \"fmt\"\n\nfunc sendData(ch chan&lt;- int) {\n\n    ch &lt;- 100 \u002F\u002F 向通道发送数据\n\n}\n\nfunc main() {\n\n    ch := make(chan int)\n\n    go sendData(ch)\n\n    data := &lt;-ch \u002F\u002F 从通道接收数据\n\n    fmt.Println(\"Received data:\", data)\n\n}\n```\n\n## 协程的调度\n\nGo 语言的协程调度器采用了一种称为 “M:N” 的调度模型，即将 M 个协程映射到 N 个操作系统线程上执行。调度器通过合理地分配协程到线程上，充分利用多核处理器的性能。\n\n调度器主要包含三个核心组件：\n\n\n\n*   **G（Goroutine）**：表示协程，包含了协程的执行栈、程序计数器等信息。\n\n*   **M（Machine）**：表示操作系统线程，负责执行协程。\n\n*   **P（Processor）**：表示处理器，它是连接 G 和 M 的桥梁，用于管理协程队列和提供执行环境。每个 P 都有一个本地的协程队列，调度器会优先调度本地队列中的协程，以提高缓存利用率。\n\n当一个协程因等待 I\u002FO 操作、通道操作或其他阻塞事件而暂停时，Go 调度器会将其从当前的操作系统线程上移开，然后调度另一个就绪的协程在该线程上执行，从而充分利用 CPU 资源。\n\n## 协程的应用场景\n\n协程在 Go 语言中有着广泛的应用场景，例如：\n\n\n\n*   **网络编程**：在处理大量的网络连接时，每个连接可以由一个协程来处理，实现高并发的网络服务。\n\n*   **数据处理**：对于需要并行处理的大量数据，可以将数据分成多个部分，由不同的协程同时处理，提高处理效率。\n\n*   **定时任务**：可以通过协程来执行定时任务，如定期清理缓存、定期发送心跳包等。\n\n总之，Go 语言的协程为并发编程提供了一种高效、简洁的解决方案，使得开发者能够更加轻松地编写出高性能的并发程序。掌握协程的使用和原理，对于 Go 语言开发者来说至关重要。\n","#Learn more about Go language collaboration\n\n! [go](https:\u002F\u002Fwallpapercave.com\u002Fwp\u002Fwp7041189.jpg)\n\n\nIn today's software development field, concurrent programming has become a key technology to improve program performance and responsiveness. In Go, Goroutine, as a lightweight concurrent execution unit, has become the core advantage of Go's concurrent programming due to its efficient and concise characteristics.\n\n##Basic concepts of coroutines\n\nCoroutines are user-mode threads unique to the Go language. They are managed by the Go runtime rather than the operating system kernel. Compared with traditional operating system threads, the cost of creating and destroying coroutines is extremely low and requires very few memory resources. Usually, a coroutine only requires a few KB of stack space, and the stack can be dynamically expanded and shrunk as needed. This makes it easy to create thousands or even millions of coroutines in a Go program without placing too much burden on the system.\n\n##Differences between coroutines and processes and threads\n\n\n\n*   ** Process **: A process is the basic unit of resource allocation and scheduling by the operating system. Each process has independent memory space and system resources. Switching between processes consumes a lot of system resources because it involves operations such as saving and restoring memory contexts.\n\n*   ** Thread **: A thread is an execution unit within a process. A process can contain multiple threads that share the process's memory space and system resources. Although the switching cost of threads is lower than that of processes, it still requires scheduling by the operating system kernel, which involves certain overhead.\n\n*   ** Coroutines **: Coroutines run in user mode, and their scheduling is completely controlled by the Go runtime, without the participation of the operating system kernel. Switching between coroutines only requires saving and restoring a small number of register states, with minimal overhead. Moreover, multiple coroutines can run on the same operating system thread, achieving concurrent execution through the Go runtime scheduler.\n\n##Creating and launching coroutine\n\nIn Go, creating and starting a coroutine is very simple, just adding the keyword 'go' before a function or method call. For example:\n\n\n\n```\npackage main\n\nimport \"fmt\"\n\nfunc sayHello() {\n\n    fmt.Println(\"Hello, Goroutine! \")\n\n}\n\nfunc main() {\n\n    go sayHello() \u002F\u002FStart a coroutine to execute the sayHello function\n\n    \u002F\u002FThe main function waits for a while to ensure that the coroutine has a chance to execute\n\n    time.Sleep(time.Second)\n\n}\n```\n\nIn the above code, the 'go sayHello()' statement starts a new coroutine to execute the 'sayHello' function. It should be noted that the coroutine in which the main function (main function) is located is the entry to the program. If the main coroutine completes execution, the program will exit, regardless of whether other coroutines have completed execution. So in the example, the 'time.Sleep' function is used to make the main coroutine wait for a period of time to ensure that the newly launched coroutine can execute.\n\n##Communication between coroutines\n\nCommunication and synchronization between multiple coroutines is needed to complete tasks collaboratively. Go provides a Channel mechanism to achieve secure communication between coroutines. A channel is like a pipe through which coroutines can send and receive data. The channel ensures data synchronization and avoids race conditions caused by multiple coroutines accessing shared resources at the same time.\n\nTo create a channel, you can use the 'make' function to specify the types of elements in the channel. For example:\n\n\n\n```\nch := make(chan int) \u002F\u002FCreate a channel that can pass data of type int\n```\n\nThe coroutine can send data to or receive data from the channel through the ` -` operator. The syntax for sending data is 'ch-data', and the syntax for receiving data is 'variable-ch'. For example:\n\n\n\n```\npackage main\n\nimport \"fmt\"\n\nfunc sendData(ch chan&lt;- int) {\n\n    ch- 100 \u002F\u002FSend data to channel\n\n}\n\nfunc main() {\n\n    ch := make(chan int)\n\n    go sendData(ch)\n\n    data :=-ch \u002F\u002FReceive data from channel\n\n    fmt.Println(\"Received data:\", data)\n\n}\n```\n\n##Scheduling of coroutines\n\nGo's coroutine scheduler adopts a scheduling model called \"M:N\", which maps M coroutines to N operating system threads for execution. Scheduler takes full advantage of the performance of multi-core processors by rationally allocating coroutines to threads.\n\nThe scheduler mainly includes three core components:\n\n\n\n*   **G (Goroutine)**: Represents a coroutine, which contains information such as the coroutine's execution stack and program counters.\n\n*   **M (Machine)**: Represents the operating system thread, responsible for executing the coroutine.\n\n*   **P (Processor)**: Represents processor, which is a bridge connecting G and M and is used to manage coroutine queues and provide an execution environment. Each P has a local coroutine queue, and the scheduler prioritizes coroutines in the local queue to improve cache utilization.\n\nWhen a coroutine pauses waiting for an I\u002FO operation, channel operation, or other blocking event, the Go scheduler removes it from the current operating system thread and schedules another ready coroutine to execute on that thread, making full use of CPU resources.\n\n##Application scenarios of coroutines\n\nCoroutines have a wide range of application scenarios in Go, such as:\n\n\n\n*   ** Network programming **: When processing a large number of network connections, each connection can be processed by a coroutine, achieving highly concurrent network services.\n\n*   ** Data processing **: For a large amount of data that needs to be processed in parallel, the data can be divided into multiple parts and processed simultaneously by different coroutines to improve processing efficiency.\n\n*   ** Timing tasks **: You can use coroutines to perform scheduled tasks, such as regular clearing of caches, regular sending of heartbeat packets, etc.\n\nIn short, Go's coroutines provide an efficient and concise solution for concurrent programming, making it easier for developers to write high-performance concurrent programs. Mastering the use and principles of coroutines is crucial for Go language developers.\n","go",0,"https:\u002F\u002Fblog4-1316398321.cos.ap-nanjing.myqcloud.com\u002Fblog5\u002F20250712010334__【哲风壁纸】WLOP-WLOP作品.png",[14],"GO",false,{"id":17,"title":18,"title_en":19},11,"python基础--什么是数据类型","python basics - what are data types",{"id":21,"title":22,"title_en":23},13,"深入剖析 Go 语言中的 map","An in-depth look at maps in Go","2025-07-24T00:00:12+08:00"]