day02-golang的goroutine和线程通信 | 青训营笔记

71 阅读4分钟

1、进程、线程、协程的关系

进程、线程和协程是并发编程中的概念,它们是不同层次的抽象。

  • 进程(Process)是计算机中运行的程序的实例。每个进程都有自己的地址空间、内存和系统资源,并由操作系统进行管理。进程是程序的执行实体,它可以拥有多个线程。
  • 线程(Thread)是进程中的执行单元,也是程序的最小执行单位。一个进程可以拥有多个线程,它们共享进程的地址空间和系统资源。线程可以独立执行,也可以协同合作完成任务。多线程可以实现并发执行,提高程序的性能和响应能力。
  • 协程(Coroutine)是一种轻量级的线程,也被称为用户级线程。协程由编程语言或者运行时环境提供支持,可以在单个线程中实现并发和并行执行。协程可以在代码中定义和使用,而不需要像线程那样依赖于操作系统的调度和管理。协程可以通过显式地挂起和恢复来实现协作式的并发。

它们的关系:

  • 一个进程可以包含多个线程,线程是进程的执行单元。
  • 多个线程共享进程的资源和地址空间,可以实现并发执行。
  • 协程是在线程中实现的,它是一种更轻量级的线程,可以实现更高效的并发和并行操作。
  • 一个线程可以拥有多个协程,协程之间可以进行协作式的并发操作。

需要注意的是,进程和线程是由操作系统进行管理和调度的,而协程是由编程语言或者运行时环境提供支持的。不同的编程语言和运行时环境对协程的实现和特性有所不同。

在并发编程中,我们可以根据需求选择使用进程、线程或协程来实现并发操作,以提高程序的性能和响应能力。

在Golang中,我们使用goroutine来实现并发。Goroutine是一种轻量级的线程,由Go运行时环境(runtime)管理。与传统的操作系统线程相比,goroutine的启动和销毁成本非常低,并且可以高效地并发执行。

2、golang的goroutine

Golang使用了一种称为"多路复用器"(multiplexer)的技术,可以在少量的操作系统线程上运行大量的goroutine。这种设计使得Golang能够轻松创建数千甚至数百万个goroutine,而不会导致系统资源的过度消耗。

创建一个goroutine非常简单,只需要在函数调用前加上go关键字即可。下面是一个简单的示例:

func main() {
	go printHello()
	fmt.Println("Main goroutine")
	time.Sleep(1 * time.Second)
}

func printHello() {
	fmt.Println("Hello from goroutine")
}

在上述示例中,我们使用"go"关键字启动了一个新的goroutine来执行printHello()函数。同时,主goroutine会继续执行fmt.Println("Main goroutine")。通过调用time.Sleep()函数,我们确保主goroutine在所有的goroutine执行完毕前等待1秒钟。运行该程序,你会看到两个消息同时打印出来,说明两个goroutine是并发执行的。

3、线程通信

Golang的并发模型还包括了通道(channel)的概念,用于实现goroutine之间的通信和同步。通道提供了一种安全、高效的方式来共享数据。通过通道,我们可以在不同的goroutine之间发送和接收数据,从而实现数据的同步和共享。下面是一个使用通道进行通信的示例:

    func main() {
    	ch := make(chan string)
    	go greet(ch)
    	message := <-ch
    	fmt.Println(message)
    }

    func greet(ch chan string) {
    	ch <- "Hello from goroutine"
    }

在上述示例中,我们创建了一个字符串类型的通道ch。然后,我们启动了一个goroutine来执行greet()函数,并将通道ch作为参数传递给它。在greet()函数中,我们向通道发送了一条消息"Hello from goroutine"。主goroutine通过<-ch接收通道中的消息,并将其打印出来。通过通道的发送和接收操作,我们实现了goroutine之间的通信和同步。

总结来说,Golang使用goroutine作为并发的基本单位,通过使用"多路复用器"技术实现高效的并发执行。通过简单的"go"关键字就可以创建和启动goroutine,而通道则提供了一种安全、高效的方式来实现goroutine之间的通信和同步。这使得Golang在编写并发程序时更加简单和高效。