Golang redis使用笔记| 青训营笔记

76 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天

什么是协程(和线程对比)

协程(Coroutine)是一种轻量级的线程,它可以在同一线程内运行,而不需要切换线程的上下文。与线程相比,协程具有更小的内存占用和更高的并发能力。在Golang中,协程是一种基本的并发单元,可以通过goroutine关键字来创建。

线程是操作系统分配的一种执行单元,每个线程都有自己的堆栈和程序计数器。在多线程应用程序中,每个线程都可以执行不同的任务,但同时需要共享相同的进程内存空间。线程的切换开销较大,并且线程之间的同步需要使用锁等机制。

相比之下,协程切换的开销非常小,因为它们在同一线程内运行。协程之间的同步可以使用通道等Golang提供的原语来实现,更为简单。

协程和线程各自的优劣

协程的优点:

  • 协程的切换开销很小,可以在同一线程内运行,因此协程的并发能力更高。
  • 协程不需要像线程那样使用锁等机制进行同步,因此代码更简洁。
  • 协程的内存占用比线程更小。

线程的优点:

  • 线程是由操作系统分配的,可以在不同的CPU核心上执行,并且可以使用操作系统提供的多线程库来进行同步和通信。
  • 线程可以利用多核CPU的优势,因此在某些情况下可以比协程更快。

Go使用协程的例子

下面是一个使用协程并发执行任务的例子:

package main

import (
	"fmt"
	"sync"
	"time"
)

func worker(id int, wg *sync.WaitGroup, jobs <-chan int, results chan<- int) {
	defer wg.Done()

	for j := range jobs {
		fmt.Printf("Worker %d started job %d\n", id, j)
		time.Sleep(time.Second)
		fmt.Printf("Worker %d finished job %d\n", id, j)
		results <- j * 2
	}
}

func main() {
	numJobs := 10
	jobs := make(chan int, numJobs)
	results := make(chan int, numJobs)

	var wg sync.WaitGroup

	// 创建3个协程
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go worker(i, &wg, jobs, results)
	}

	// 添加10个任务到任务队列中
	for j := 1; j <= numJobs; j++ {
		jobs <- j
	}
	close(jobs)

	// 等待所有协程完成任务
	wg.Wait()

	// 获取结果
	for a := 1; a <= numJobs; a++ {
		<-results
	}
}

例子中使用一个sync.WaitGroup来同步协程的执行。每个协程执行完成后,都会调用wg.Done()来通知WaitGroup,主函数使用wg.Wait()来等待所有协程都执行完成后结束。此外,我们还使用了defer语句来确保在协程退出前调用wg.Done()。

在这个例子中,我们还保留了原来的协程数量和任务分配策略。如果需要改变协程数量或任务分配策略,只需要调整i的取值和任务添加的逻辑即可。