Goroutine은 Go 언어로 구현된 경량 스레드입니다. 스레드 기반의 경량 추상화이며 Go 런타임에 의해 관리됩니다. 고루틴을 사용하면 매우 저렴한 비용으로 동일한 주소 공간에서 여러 함수나 메소드를 병렬로 실행할 수 있으며, 생성 및 소멸 비용이 훨씬 저렴하고 스케줄링이 스레드와 독립적입니다.
이 튜토리얼의 운영 환경: Windows 7 시스템, GO 버전 1.18, Dell G3 컴퓨터.
소켓 네트워크 프로그램을 작성할 때 패킷을 보내고 받는 소켓마다 스레드를 할당할 수 있도록 스레드 풀을 미리 준비해야 합니다. 개발자는 스레드 간 여러 작업을 자주 전환하여 발생하는 효율성 손실을 피하면서 적시에 처리하기 위해 각 작업을 CPU에 할당할 수 있도록 스레드 수와 CPU 수 사이의 대응 관계를 설정해야 합니다. .
하지만 스레드 풀은 논리 작성자를 위한 스레드 할당을 위한 추상 메커니즘을 제공합니다. 그러나 언제 어디서나 발생할 수 있는 동시성 및 스레드 처리 요구 사항에 직면했을 때 스레드 풀은 그리 직관적이고 편리하지 않습니다. 메커니즘이 있습니까? 사용자가 충분한 작업을 할당하면 시스템은 이러한 작업이 가능한 한 동시에 실행될 수 있도록 사용자가 작업을 CPU에 할당하도록 자동으로 도울 수 있습니다. 이 메커니즘을 Go 언어에서는 고루틴이라고 합니다.
goroutine은 Go 언어로 구현된 경량 스레드이며 Go 런타임에 의해 관리됩니다. Go 프로그램은 각 CPU에 고루틴의 작업을 지능적으로 할당합니다.
고루틴은 스레드 기반의 경량 추상화입니다. 이를 통해 매우 저렴한 비용으로 동일한 주소 공간에서 여러 함수나 메서드를 병렬로 실행할 수 있습니다. 스레드에 비해 생성 및 삭제 비용이 훨씬 저렴하고 예약이 스레드와 독립적입니다.
Go 프로그램은 메인 패키지의 main() 함수에서 시작됩니다. 프로그램이 시작되면 Go 프로그램은 main() 함수에 대한 기본 고루틴을 생성합니다.
일반 함수를 사용하여 고루틴 만들기
Go 프로그램에서 go 키워드를 사용하여 함수에 대한 고루틴을 만듭니다. 함수는 여러 고루틴으로 생성될 수 있으며, 하나의 고루틴은 하나의 함수에 대응해야 합니다.
1) 형식
공용 함수에 대한 고루틴 생성은 다음과 같이 작성됩니다.
go 函数名( 参数列表 )
함수 이름: 호출할 함수의 이름입니다.
매개변수 목록: 함수 호출 시 전달해야 하는 매개변수입니다.
go 키워드를 사용하여 고루틴을 생성하면 호출된 함수의 반환 값이 무시됩니다.
고루틴에서 데이터를 반환해야 하는 경우 나중에 소개되는 채널 기능을 사용하여 고루틴의 데이터를 채널을 통해 반환 값으로 전달하세요.
2) 예제
go 키워드를 사용하여 running() 함수를 동시에 실행하고 매초마다 카운터를 인쇄하는 동시에 메인 고루틴은 사용자 입력을 기다리는 동안 두 작업을 동시에 수행할 수 있습니다. 아래 코드를 참조하세요.
package main import ( "fmt" "time" ) func running() { var times int // 构建一个无限循环 for { times++ fmt.Println("tick", times) // 延时1秒 time.Sleep(time.Second) } } func main() { // 并发执行程序 go running() // 接受命令行输入, 不做任何事情 var input string fmt.Scanln(&input) }
명령줄 출력은 다음과 같습니다.
코드가 실행된 후 명령줄은 계속해서 틱을 출력하며 fmt.Scanln()을 사용하여 사용자 입력을 받을 수 있습니다. . 두 단계는 동시에 수행될 수 있습니다.
코드 설명은 다음과 같습니다.
12번째 줄, for를 사용하여 무한 루프를 형성합니다.
라인 13에서 times 변수는 루프에서 계속 증가합니다.
14번째 줄, times 변수의 값을 출력합니다.
라인 17, 시간을 사용하세요. 1초 동안 잠을 자다가 계속 반복하세요.
라인 25, go 키워드를 사용하여 running() 함수를 동시에 실행합니다.
29번째 줄, Enter 키를 누를 때까지 사용자 입력을 받아들이면 입력 내용이 입력 변수에 쓰여지고 반환되며 전체 프로그램이 종료됩니다.
이 코드의 실행 순서는 아래 그림과 같습니다.
그림: 동시 실행 다이어그램
이 예에서 Go 프로그램이 시작되면 런타임(런타임)은 기본적으로 main() 함수에 대한 고루틴을 생성합니다. main() 함수의 고루틴에서 go running 문이 실행되면 running() 함수에 속한 고루틴이 생성되고, running() 함수는 자신의 고루틴에서 실행을 시작한다. 이 시점에서 main()은 계속 실행되며 Go 프로그램의 스케줄링 메커니즘을 통해 두 개의 고루틴이 동시에 작동합니다.
익명 함수를 사용하여 고루틴 만들기
go 키워드 다음에 익명 함수 또는 클로저에 대한 고루틴을 시작할 수도 있습니다.
1) 익명 함수를 사용하여 고루틴을 생성하는 형식
익명 함수나 클로저를 사용하여 고루틴을 생성할 때 go 이후에 함수 정의 부분을 작성하는 것 외에 익명 함수의 호출 매개변수도 추가해야 합니다. , 형식은 다음과 같습니다.
go func( 参数列表 ){ 函数体 }( 调用参数列表 )
위치:
매개변수 목록: 함수 본문의 매개변수 변수 목록입니다.
함수 본문: 익명 함수의 코드입니다.
调用参数列表:启动 goroutine 时,需要向匿名函数传递的调用参数。
2) 使用匿名函数创建goroutine的例子
在 main() 函数中创建一个匿名函数并为匿名函数启动 goroutine。匿名函数没有参数。代码将并行执行定时打印计数的效果。参见下面的代码:
package main import ( "fmt" "time" ) func main() { go func() { var times int for { times++ fmt.Println("tick", times) time.Sleep(time.Second) } }() var input string fmt.Scanln(&input) }
代码说明如下:
第 10 行,go 后面接匿名函数启动 goroutine。
第 12~19 行的逻辑与前面程序的 running() 函数一致。
第 21 行的括号的功能是调用匿名函数的参数列表。由于第 10 行的匿名函数没有参数,因此第 21 行的参数列表也是空的。
扩展知识:Goroutine与线程的区别
许多人认为goroutine比线程运行得更快,这是一个误解。Goroutine并不会更快,它只是增加了更多的并发性。当一个goroutine被阻塞(比如等待IO),golang的scheduler会调度其他可以执行的goroutine运行。与线程相比,它有以下的几个优点:
内存消耗更少:
Goroutine所需要的内存通常只有2kb,而线程则需要1Mb(500倍)
创建与销毁的开销更小:
由于线程创建时需要向操作系统申请资源,并且在销毁时将资源归还,因此它的创建和销毁的开销比较大。相比之下,goroutine的创建和销毁是由go语言在运行时自己管理的,因此开销更低。
切换开销更小:
只是goroutine之于线程的主要区别,也是golang能够实现高并发的主要原因。线程的调度方式是抢占式的,如果一个线程的执行时间超过了分配给它的时间片,就会被其他可执行的线程抢占。在线程切换的过程中需要保存/恢复所有的寄存器信息,比如16个通用寄存器,PC(Program Counter)、SP(Stack Pointer)段寄存器等等。而goroutine的调度是协同式的,它不会直接地与操作系统内核打交道。当goroutine进行切换的时候,之后很少量的寄存器需要保存和恢复(PC和SP)。因此goroutine的切换效率更高。
위 내용은 Go 언어로 된 고루틴이란 무엇인가요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!