Go从入门到精通——轻量级线程(goroutine)——根据需要随时创建的“线程”

轻量级线程(goroutine)——根据需要随时创建的“线程”

一、什么是 goroutine?

  在编写 Socket 网络程序时,需要提前准备一个线程池为每一个 Socket 的收发包分配一个线程。开发人员需要为 线程数量 和 CPU 间建立一个对应关系,以保证每个任务能及时地分配到 CPU 上进行处理,同时避免多个任务频繁地在线程间切换执行而损失效率。

  虽然,线程池为逻辑编写者提供了线程分配的抽象机制。但是,如果对随时随地可能发生的并发和线程处理需求,线程池就不是非常直观和方便了。能否有一种机制:使用者分配足够多的任务,系统能自动帮助使用者把任务分配到 CPU 上,让这些任务尽量并发运作。 

  这种机制在 Go 语言中被称为 goroutine。

 

二、使用普通函数创建 goroutine

  Go 程序中使用 go 关键字为一个函数创建一个 goroutine。一个函数可以被创建多个 goroutine,一个 goroutine 必定对应一个函数。

  为一个普通函数创建 goroutine 的写法如下:

go 函数名(参数列表)
 
    函数名:要调用的函数名。
    参数列表:调用函数需要传入的参数。
提示:如果需要在 goroutine 中返回数据,请使用通道(channel),通过通道把数据从 goroutine 中作为返回值传出

  举个例子:

  使用 go 关键字,将 running() 函数并发执行,每隔一秒打印一次计数器,而 main 的 goroutine 则等待用户输入,两个行为可以同时进行。

package main

import (
	"fmt"
	"time"
)

func running() {
	var times int

	// 构建一个无限循环
	for {
		times++                    // times 变量在每次循环中不断自增。
		fmt.Println("tick", times) // 输出变量 time 的值。

		//延时1秒
		time.Sleep(time.Second) // 延迟 1秒,没啥好解释的。
	}
}

func main() {

	//并发执行程序
	go running() // 注意,这里使用普通函数创建 goroutine,并发运行。

	//接受命令行输入,不做任何事情
	var input string // 同时接受用户输入,直到按 Enter 键时将输入的内容写入 inut 变量中并返回,整个程序终止。
	fmt.Scanln(&input)

}

  程序输出如下:

Starting: D:\go-testfiles\bin\dlv.exe dap --check-go-version=false --listen=127.0.0.1:55003 from d:\go-testfiles
DAP server listening at: 127.0.0.1:55003
Type 'dlv help' for list of commands.
tick 1
tick 2
tick 3
tick 4
tick 5
tick 6
tick 7
tick 8
tick 9
tick 10

  代码执行后,命令行会不断输出 tick,同时可以使用 fmt.Scanln() 接受用户输入。两个环节可以同时进行。

  在这个例子中, Go 程序在启动时,运行时(runtime)会默认为 main() 函数创建一个 goroutine。在 main() 函数的 goroutine 中执行到 go running 语句时,归属于 running() 函数的 goroutine 被创建,running() 函数开始在自己的 goroutine 中执行。此时,main() 继续执行,两个 goroutine 通过 Go 程序的调度机制同时运作。 

posted @ 2022-05-10 23:24  左扬  阅读(161)  评论(0编辑  收藏  举报
levels of contents