go并发(进程、线程、协程)

背景

        go强大的多线程能力很强大,能并发处理大量的任务。

详细案例分类

        主要介绍go中的进程、线程、协程这三个东西。它们的关系按照内存大小的关系依次是进程 > 线程 > 协程(一般一个协程2K)。

进程

        进程基本上是一个正在执行的程序,它是操作系统中最小的资源分配单位。比如电脑上运行的一个软件就是一个进程。
        go开启进程的方式有三种,本质上都是通过命令去启动电脑上的软件比如nodejs。

package utils

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"syscall"
)

func Process() {
	// 创建进程方式一
	grepCmd := exec.Command("node", "-v") // cmd命令
	grepIn, _ := grepCmd.StdinPipe()      // 写入管道
	grepOut, _ := grepCmd.StdoutPipe()    // 输出管道
	grepCmd.Start()                       // 开始执行命令
	grepIn.Write([]byte("写入的数据"))         // 写入的数据
	grepIn.Close()                        // 关闭写入通道
	grepBytes, _ := io.ReadAll(grepOut)   // 读取输出的数据
	grepCmd.Wait()                        // 等待进程进程
	fmt.Println("> grep hello, pid: ", grepCmd.Process.Pid)
	fmt.Println(string(grepBytes))

	// 创建进程方式二
	nodeCmd := exec.Command("node", "-v")
	cmdOutput, err := nodeCmd.Output()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(cmdOutput, string(cmdOutput)) // buffer转utf8
	}

	binary, lookErr := exec.LookPath("node")
	if lookErr != nil {
		panic(lookErr)
	}
	args := []string{"node", "-v"}
	env := os.Environ()
	execErr := syscall.Exec(binary, args, env)
	if execErr != nil {
		panic(execErr)
	}

	println("process进程")
}

线程(轻量级进程)

        线程可以看成是轻量级的进程,线程内存大小会根据处理器进行自动分配。
        其中根据go的两种gc方式cgo和go线程数量是不同的,其中cgo会释放掉空闲的线程提高性能,比如有用到的net包中的LookupHost方法。
        go:GODEBUG=netdns=go go run main.go
        cgo:GODEBUG=netdns=cgo go run main.go

package utils

import (
	"fmt"
	"runtime"
	"runtime/pprof"
	"sync"
)

var threadProfile = pprof.Lookup("threadcreate")

func ThreadTest() {
	fmt.Printf(("线程数%d个"), threadProfile.Count())

	var wg sync.WaitGroup
	wg.Add(10) // 计时器如果为0则所有Wait上阻塞的协程都会释放,为负数则会panic
	for i := 0; i < 10; i++ {
		go func() {
			defer wg.Done()
			println("执行任务")
			runtime.LockOSThread() // 杀掉线程(如果协程在退出的时候没有unlock这个线程,那么这个线程会被终止)
		}()
	}
	wg.Wait() // 等待线程执行结束
	fmt.Printf(("线程数%d个"), threadProfile.Count())
	println("thread线程")
}

协程(轻量级线程)

        这里就和channel(https://blog.csdn.net/qq_40816649/article/details/132898741?spm=1001.2014.3001.5501)一起说吧,协程可以看成是轻量级线程,go多线程能力强处理并发靠的就是协程。
        在go中启动一个协程很简单在方法前面加上go关键词,就会启动一个runtime运行函数和当前的go线程不在用一个线程,所以这里为了数据安全go提倡通过通信(channel)共享内存而不是通过共享内存而实现通信。

package utils

import (
	"fmt"
	"time"
)

func worker(id int, jobs <-chan int, results chan<- int) {
	for j := range jobs {
		fmt.Println("worker", id, "processing job", j)
		time.Sleep(time.Second)
		results <- j * 2
	}
}
func Goroutine() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)
	for w := 1; w <= 3; w++ {
		// go关键词启动一个新的runtime运行函数worker(和当前的go线程不在同一个栈)(协程)
		go worker(w, jobs, results)
	}
	for j := 1; j <= 9; j++ {
		jobs <- j
	}
	for a := 1; a <= 9; a++ {
		<-results
	}
	println("goroutine轻量级线程也叫协程")
}

结论

        go的学习之路还很长期望后续工作中能碰到go的应用场景。

所谓的弱,就是一种罪,所谓理想,只是同时拥有实力的人才能说的“现实”

你可能感兴趣的:(go,java)