Go Web 实战编程-并发、携程

我爱海鲸 2024-06-13 17:39:19 go语言学习

简介channel、goroutine

1、chan1

package main

import (
	"fmt"
)

func main() {
	ch := make(chan string) // 构建一个通道
	go func() {             // 开启一个并发匿名函数
		fmt.Println("开始协程") // 通过通道通知main的协程
		ch <- "signal"
		fmt.Println("退出协程")
	}()
	fmt.Println("等待协程")
	<-ch // 等待匿名协程
	fmt.Println("完成")
}

2、chan2:

package main

import (
	"fmt"
)

func Sum(s []int, ch chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	ch <- sum // 把 sum 发送到通道 ch
}

func main() {
	s := []int{6, 7, 8, -9, 1, 8}
	ch := make(chan int)
	go Sum(s[:len(s)/2], ch)
	go Sum(s[len(s)/2:], ch)
	a, b := <-ch, <-ch // 从通道 ch 中接收
	fmt.Println(a, b, a+b)
}

后进先出

3、chan3:

package main

import "fmt"

func main() {
	// 这里我们定义了一个可以存储整数类型的带缓冲通道,缓冲区大小为3
	ch := make(chan int, 3)
	// 因为 ch 是带缓冲的通道,我们可以同时发送两个数据
	// 而不用立刻需要去同步读取数据
	ch <- 6
	ch <- 7
	ch <- 8
	// 获取这三个数据
	fmt.Println(<-ch)
	fmt.Println(<-ch)
	fmt.Println(<-ch)
}

4、chan4:

package main

import (
	"fmt"
)

func fibonacci(n int, ch chan int) {
	a, b := 0, 1
	for i := 0; i < n; i++ {
		ch <- a
		a, b = b, a+b
	}
	close(ch)
}

func main() {
	ch := make(chan int, 6)
	go fibonacci(cap(ch), ch)
	for j := range ch {
		fmt.Println(j)
	}
}

5、channel:

package main

func main() {
	// 创建一个字符串通道
	ch := make(chan string)
	// 尝试将sleep通过通道发送
	ch <- "sleep"
}

这里会发生死锁

package main

import (
	"fmt"
	"runtime"
	"sync"
)

var Counter int

func Count(lock *sync.Mutex) {
	lock.Lock() // 上锁
	Counter++
	fmt.Println("Counter =", Counter)
	lock.Unlock() // 解锁
}

func main() {
	lock := &sync.Mutex{}
	for i := 0; i < 6; i++ {
		go Count(lock)
	}
	for {
		lock.Lock() // 上锁
		c := Counter
		lock.Unlock()     // 解锁
		runtime.Gosched() // 出让时间片
		if c >= 6 {
			break
		}
	}
}

 

 

package main

import (
	"fmt"
)

func Counting(ch chan int) {
	ch <- 1
	fmt.Println("Counting")
}

func main() {
	channels := make([]chan int, 6)
	for i := 0; i < 6; i++ {
		channels[i] = make(chan int)
		go Counting(channels[i])
	}

	for _, ch := range channels {
		fmt.Println(<-ch)
	}

	//select {
	//case <- chan1:
	//	// 如果chan1成功读到数据
	//
	//case chan2 <- 1:
	//	// 如果成功向chan2写入数据
	//
	//default:
	//	// 默认分支
	//}
	//
	//timeout := make(chan bool, 1)
	//
	//go func() {
	//	time.Sleep(1e9)
	//	timeout <- true
	//}()
	//
	//switch {
	//case <- ch:
	//	// 从ch中读取到数据
	//
	//case <- timeout:
	//	// 没有从ch中读取到数据,但从timeout中读取到了数据
	//}
}

 

package main

import "fmt"

func main() {
	ch := make(chan int, 2)
	// 发送
	go func() {
		for i := 0; i < 6; i++ {
			fmt.Printf("Sender: sending element %v...\n", i)
			ch <- i
		}
		fmt.Println("Sender: close the channel...")
		close(ch)
	}()

	// 接收
	for {
		elem, ok := <-ch
		if !ok {
			fmt.Println("Receiver: closed channel")
			break
		}
		fmt.Printf("Receiver: received an element: %v\n", elem)
	}

	fmt.Println("End.")
}

 

package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

var wg sync.WaitGroup

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	ch := make(chan int)
	wg.Add(2)
	go playTableTennis("Jim", ch)
	go playTableTennis("Jack", ch)
	ch <- 1
	wg.Wait()

}

func playTableTennis(player string, ch chan int) {
	defer wg.Done()

	for {
		ball, ok := <-ch
		if !ok {
			fmt.Printf("%s has won!\n", player)
			return
		}
		n := rand.Intn(100)
		if n%13 == 0 {
			fmt.Printf("player %s missed!\n", player)
			close(ch)
			return
		}
		ball++
		fmt.Printf("play %s has hit the ball, his score is %d\n", player, ball)
		ch <- ball
	}
}

 

package main

import "fmt"

func main() {
	ch := make(chan string, 3)
	ch <- "i"
	ch <- "love"
	ch <- "you"
	close(ch)
	fmt.Println(<-ch)
	fmt.Println(<-ch)
	fmt.Println(<-ch)
}

 

package main

import "fmt"

func main() {

	var a, b int
	go func() {
		a = 1
		fmt.Println("a:", b, " ")
	}()
	go func() {
		b = 1
		fmt.Println("b:", a, " ")
	}()
}

 

6、channel-filter

package main

import "fmt"

// 生成自增的整数
func IntegerGenerator() chan int {
	var ch chan int = make(chan int)

	go func() { // 开出一个goroutine
		for i := 2; ; i++ {
			ch <- i // 直到通道索要数据,才把i添加进通道
		}
	}()

	return ch
}

func Filter(in chan int, number int) chan int {
	// 输入一个整数队列,筛出是number倍数的, 不是number的倍数的放入输出队列
	// in:  输入队列
	out := make(chan int)

	go func() {
		for {
			i := <-in // 从输入中取一个

			if i%number != 0 {
				out <- i // 放入输出通道
			}
		}
	}()

	return out
}

func main() {
	const max = 100               // 找出100以内的所有素数
	numbers := IntegerGenerator() // 初始化一个整数生成器
	number := <-numbers           // 从生成器中抓一个整数(2), 作为初始化整数

	for number <= max { // number作为筛子,当筛子超过max的时候结束筛选
		fmt.Println(number)               // 打印素数, 筛子即一个素数
		numbers = Filter(numbers, number) //筛掉number的倍数
		number = <-numbers                // 更新筛子
	}
}

7、channel-listener

package main

import (
	"fmt"
)

func foo(i int) chan int {
	ch := make(chan int)
	go func() { ch <- i }()
	return ch
}

func main() {
	ch1, ch2, ch3 := foo(3), foo(6), foo(9)

	ch := make(chan int)

	// 开一个goroutine监视各个通道数据输出并收集数据到通道ch
	go func() {
		for {
			// 监视ch1, ch2, ch3的流出,并全部流入通道ch
			select {
			case v1 := <-ch1:
				ch <- v1
			case v2 := <-ch2:
				ch <- v2
			case v3 := <-ch3:
				ch <- v3
			}

			//timeout 是一个计时通道, 如果达到时间了,就会发一个信号出来
			//timeout := time.After(1 * time.Second)
			//for isTimeout := false; !isTimeout; {
			//	select { // 监视通道ch1, ch2, ch3, timeout通道的数据流出
			//	case v1 := <-ch1:
			//		fmt.Printf("received %d from ch1", v1)
			//	case v2 := <-ch2:
			//		fmt.Printf("received %d from ch2", v2)
			//	case v3 := <-ch3:
			//		fmt.Printf("received %d from ch3", v3)
			//	case <-timeout:
			//		isTimeout = true // 超时
			//	}
			//}
		}
	}()

	// 阻塞主线,取出通道ch的数据
	for i := 0; i < 3; i++ {
		fmt.Println(<-ch)
	}

}

8、channel-quit

package main

import (
	"fmt"
)

func main() {

	ch, quit := make(chan int), make(chan int)

	go func() {
		ch <- 8   // 添加数据
		quit <- 1 // 发送完成信号
	}()

	for isQuit := false; !isQuit; {
		// 监视通道ch的数据流出
		select {
		case v := <-ch:
			fmt.Printf("received %d from ch", v)
		case <-quit:
			isQuit = true // quit通道有输出,关闭for循环
		}
	}
}

9、channel-receive

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int) // 构建一个通道
	go func() {          // 开启一个并发匿名函数
		for i := 6; i <= 8; i++ { // 从6循环到8
			ch <- i                 // 发送6到8之间的数值
			time.Sleep(time.Second) // 每次发送完时等待
		}
	}()

	for receive := range ch { // 遍历接收通道数据
		fmt.Println(receive) // 打印通道数据
		if receive == 8 {    // 当遇到数据8时, 退出接收循环
			break
		}
	}
}

10、concurrent

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"io"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"sync"
	"time"
)

const (
	DataRoot     = "./tmp/" // 存放封面图的根目录
	TimeoutLimit = 10       // 设置超时时间
)

// 表示章节ID和封面URL的对应关系
type VolumeCover struct {
	VolumeID int
	Url      string
	Lock     sync.Mutex
	Msg      chan string
	Flag     bool "timeout_flag"
}

// 将图片下载并保存到本地
func SaveImage(vc *VolumeCover) {
	res, err := http.Get(vc.Url)
	defer res.Body.Close()
	if err != nil {
		vc.Msg <- (strconv.Itoa(vc.VolumeID) + " HTTP_ERROR")
	}
	// 创建文件
	dst, err := os.Create(DataRoot + strconv.Itoa(vc.VolumeID) + ".jpg")
	if err != nil {
		vc.Msg <- (strconv.Itoa(vc.VolumeID) + " OS_ERROR")
	}
	// 生成文件
	io.Copy(dst, res.Body)
	// goroutine通信
	vc.Lock.Lock()
	vc.Msg <- "in"
	vc.Flag = true
	vc.Lock.Unlock()
}

func Start(name string, password string, limit int) error {
	runtime.GOMAXPROCS(4)
	sl, err := sql.Open("mysql", name+":"+password+"@/xxx?charset=utf8")
	defer sl.Close()
	if err != nil {
		return err
	}
	// 构造SELECT语句并检索
	queryStr := "SELECT VolumeID, ImageUrl FROM volume "
	if limit > 0 {
		queryStr += "limit " + strconv.Itoa(limit)
	}
	rows, err := sl.Query(queryStr)
	defer rows.Close()
	if err != nil {
		return err
	}

	// 构建列表
	i := 0
	vclist := make([]*VolumeCover, limit)
	for rows.Next() {
		vc := &VolumeCover{}
		if err := rows.Scan(&vc.VolumeID, &vc.Url); err != nil {
			return err
		}
		vc.Msg = make(chan string, 1)
		//vc.To = make(chan bool, 1)
		vc.Lock = *new(sync.Mutex)
		vclist[i] = vc
		i++
	}

	// start goroutines
	for i := 0; i < len(vclist); i++ {
		go SaveImage(vclist[i])
		go func(i int) {
			time.Sleep(TimeoutLimit * time.Second)
			if vclist[i].Flag == false {
				vclist[i].Msg <- "out"
			}
		}(i)
	}

	// 阻塞地获取结果
	for i := 0; i < len(vclist); i++ {
		func(c *VolumeCover) {
			select {
			case m := <-c.Msg:
				fmt.Println(m)
			}

		}(vclist[i])
	}
	return nil
}

11、crawer:

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
)

func Get(url string) (result string, err error) {
	resp, err1 := http.Get(url)
	if err != nil {
		err = err1
		return
	}
	defer resp.Body.Close()
	//读取网页的body内容
	buf := make([]byte, 4*1024)
	for true {
		n, err := resp.Body.Read(buf)
		if err != nil {
			if err == io.EOF {
				fmt.Println("文件读取完毕")
				break
			} else {
				fmt.Println("resp.Body.Read err = ", err)
				break
			}
		}
		result += string(buf[:n])
	}
	return
}

//将所有的网页内容爬取下来
func SpiderPage(i int, page chan<- int) {
	url := "https://github.com/search?q=go&type=Repositories&p=1" + strconv.Itoa((i-1)*50)
	fmt.Printf("正在爬取第%d个网页\n", i)
	//爬,将所有的网页内容爬取下来
	result, err := Get(url)
	if err != nil {
		fmt.Println("http.Get err = ", err)
		return
	}
	//把内容写入到文件
	filename := "page"+strconv.Itoa(i) + ".html"
	f, err1 := os.Create(filename)
	if err1 != nil {
		fmt.Println("os.Create err = ", err1)
		return
	}
	//写内容
	f.WriteString(result)
	//关闭文件
	f.Close()
	//每爬完一个,就给个值
	page <- i
}

func Run(start, end int) {
	fmt.Printf("正在爬取第%d页到%d页\n", start, end)
	//因为很有可能爬虫还没有结束下面的循环就已经结束了,所以这里就需要且到通道
	page := make(chan int)
	for i := start; i <= end; i++ {
		//将page阻塞
		go SpiderPage(i, page)
	}
	for i := start; i <= end; i++ {
		fmt.Printf("第%d个页面爬取完成\n", <-page) //这里直接将面码传给点位符,值直接从管道里取出
	}
}

func main() {
	var start, end int
	fmt.Printf("请输入起始页数字>=1:> ")
	fmt.Scan(&start)
	fmt.Printf("请输入结束页数字:> ")
	fmt.Scan(&end)
	Run(start, end)
}

 

package main

import (
	"fmt"
	"github.com/linehk/gopl/ch5/links"
	"log"
)

func crawl(url string) []string {
	fmt.Println(url)
	list, err := links.Extract(url)
	if err != nil {
		log.Print(err)
	}
	return list
}

 

12、generator

package main

import "fmt"

// 生成自增的整数
func IntegerGenerator() chan int {
	var ch chan int = make(chan int)

	// 开启 goroutine
	go func() {
		for i := 0; ; i++ {
			ch <- i // 直到通道索要数据,才把i添加进信道
		}
	}()

	return ch
}

func main() {

	generator := IntegerGenerator()

	for i := 0; i < 100; i++ { //生成100个自增的整数
		fmt.Println(<-generator)
	}
}

13、goroutine

package main

import "fmt"

func main() {

	messages := make(chan string)

	go func() { messages <- "ping" }()

	msg := <-messages
	fmt.Println(msg)
}

 

 

package main

import (
	"fmt"
	"time"
)

func Echo(s string) {
	for i := 0; i < 3; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	go Echo("go")
	Echo("web program")
}

14、multi-channel-recombination

package main

import (
	"fmt"
	"math/rand"
	"time"
)

// 这里可以是比较耗时的事情,比如计算
func doCompute(x int) int {
	time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) //模拟计算
	return 1 + x                                                // 假如1 + x是一个很费时的计算
}

// 每个分支开出一个goroutine做计算,并把计算结果发送到各自通道
func branch(x int) chan int {
	ch := make(chan int)
	go func() {
		ch <- doCompute(x)
	}()
	return ch
}

func Recombination(chs ...chan int) chan int {
	ch := make(chan int)

	for _, c := range chs {
		// 注意此处明确传值
		go func(c chan int) { ch <- <-c }(c) // 复合
	}

	return ch
}

func Recombination(branches ...chan int) chan int {
	ch := make(chan int)

	//select会尝试着依次取出各个通道的数据
	go func() {
		for i := 0; i < len(branches); i++ {
			select {
			case v1 := <-branches[i]:
				ch <- v1
			}
		}
	}()

	return ch
}

func main() {
	//返回复合结果
	result := Recombination(branch(10), branch(20), branch(30))

	for i := 0; i < 3; i++ {
		fmt.Println(<-result)
	}
}

 

package main

import (
	"fmt"
	"math/rand"
	"time"
)

// 这里可以是比较耗时的事情,比如计算
func doCompute(x int) int {
	time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) //模拟计算
	return 1 + x                                                // 假如1 + x是一个很费时的计算
}

// 每个分支开出一个goroutine做计算,并把计算结果发送到各自通道
func branch(x int) chan int {
	ch := make(chan int)
	go func() {
		ch <- doCompute(x)
	}()
	return ch
}

func Recombination(branches ...chan int) chan int {
	ch := make(chan int)

	//select会尝试着依次取出各个通道的数据
	go func() {
		for i := 0; i < len(branches); i++ {
			select {
			case v1 := <-branches[i]:
				ch <- v1
			}
		}
	}()

	return ch
}

func main() {
	//返回复合结果
	result := Recombination(branch(10), branch(20), branch(30))

	for i := 0; i < 3; i++ {
		fmt.Println(<-result)
	}
}

 

15、notification

package main

import "fmt"

func SendNotification(user string) chan string {

	//......此处省略查询数据库获取新消息。
	//声明一个通道来保存消息
	notifications := make(chan string, 500)

	// 开启一个通道
	go func() {
		//将消息放入通道
		notifications <- fmt.Sprintf("Hi %s, welcome to our site!", user)
	}()

	return notifications
}

func main() {
	barry := SendNotification("barry")     //  获取barry的消息
	shirdon := SendNotification("shirdon") // 获取shirdon的消息

	// 获取消息的返回
	fmt.Println(<-barry)
	fmt.Println(<-shirdon)
}

16、picShow

package main

import (
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	"io/ioutil"
	"log"
	"os"

	"github.com/golang/freetype"
)

func main() {
	//需要加水印的图片
	imgfile, _ := os.Open("./pic.jpg")
	defer imgfile.Close()

	jpgimg, _ := jpeg.Decode(imgfile)

	img := image.NewNRGBA(jpgimg.Bounds())

	for y := 0; y < img.Bounds().Dy(); y++ {
		for x := 0; x < img.Bounds().Dx(); x++ {
			img.Set(x, y, jpgimg.At(x, y))
		}
	}
	//拷贝一个字体文件到运行目录
	fontBytes, err := ioutil.ReadFile("simsun.ttc")
	if err != nil {
		log.Println(err)
	}

	font, err := freetype.ParseFont(fontBytes)
	if err != nil {
		log.Println(err)
	}

	f := freetype.NewContext()
	f.SetDPI(72)
	f.SetFont(font)
	f.SetFontSize(12)
	f.SetClip(jpgimg.Bounds())
	f.SetDst(img)
	f.SetSrc(image.NewUniform(color.RGBA{R: 255, G: 0, B: 0, A: 255}))

	pt := freetype.Pt(img.Bounds().Dx()-200, img.Bounds().Dy()-12)
	_, err = f.DrawString("Shirdon", pt)

	//draw.Draw(img,jpgimg.Bounds(),jpgimg,image.ZP,draw.Over)

	//保存到新文件中
	newfile, _ := os.Create("./aaa.jpg")
	defer newfile.Close()

	err = jpeg.Encode(newfile, img, &jpeg.Options{100})
	if err != nil {
		fmt.Println(err)
	}
}

 

package main

import (
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"log"
	"os"
)

func main() {

	rectangle := "rectangle.png"

	rectImage := image.NewRGBA(image.Rect(0, 0, 200, 200))
	green := color.RGBA{0, 100, 0, 255}

	draw.Draw(rectImage, rectImage.Bounds(), &image.Uniform{green}, image.ZP, draw.Src)

	file, err := os.Create(rectangle)
	if err != nil {
		log.Fatalf("failed create file: %s", err)
	}
	png.Encode(file, rectImage)
}

 

17、race

package main

import "fmt"

func main() {
	c := make(chan bool)
	m := make(map[string]string)
	go func() {
		m["a"] = "one" // 第一个冲突访问.
		c <- true
	}()
	m["b"] = "two" // 第一个冲突访问
	<-c
	for k, v := range m {
		fmt.Println(k, v)
	}
}

18、rand-generator

package main

import "fmt"

func randGenerator() chan int {
	ch := make(chan int)

	go func() {
		for {
			//select会尝试执行各个case, 如果都可以执行,那么随机选一个执行
			select {
			case ch <- 0:
			case ch <- 1:
			}
		}
	}()

	return ch
}

func main() {
	//初始化一个随机生成器
	generator := randGenerator()

	//测试,打印10个随机数
	for i := 0; i < 10; i++ {
		fmt.Println(<-generator)
	}
}

19、sync_mutex

package main

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

func main() {
	var mutex sync.Mutex
	wait := sync.WaitGroup{}
	fmt.Println("Locked")
	mutex.Lock()
	for i := 1; i <= 5; i++ {
		wait.Add(1)
		go func(i int) {
			fmt.Println("Not lock:", i)
			mutex.Lock()
			fmt.Println("Lock:", i)
			time.Sleep(time.Second)
			fmt.Println("Unlock:", i)
			mutex.Unlock()
			defer wait.Done()
		}(i)
	}
	time.Sleep(time.Second)
	fmt.Println("Unlocked")
	mutex.Unlock()
	wait.Wait()
}

20、sync_once

package main

import (
	"fmt"
	"sync"
)

func main() {
	var once sync.Once
	onceBody := func() {
		fmt.Println("test only once,这里只打印一次!") //打印
	}
	done := make(chan bool)
	for i := 0; i < 6; i++ {
		go func() {
			once.Do(onceBody) //确保只背执行一次
			done <- true
		}()
	}
	for i := 0; i < 6; i++ {
		<-done
	}
}

 

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup
var once sync.Once

func func1(ch1 chan<- int) {
	defer wg.Done()
	for i := 0; i < 10; i++ {
		ch1 <- i
	}
	close(ch1)
}

func func2(ch1 <-chan int, ch2 chan<- int) {
	defer wg.Done()
	for {
		x, ok := <-ch1
		if !ok {
			break
		}
		ch2 <- 2 * x
	}

	once.Do(func() { close(ch2) }) // 确保某个操作只执行一次
}

func main() {
	ch1 := make(chan int, 10)
	ch2 := make(chan int, 10)

	wg.Add(3)

	go func1(ch1)
	go func2(ch1, ch2)
	go func2(ch1, ch2)

	wg.Wait()

	for ret := range ch2 {
		fmt.Println(ret)
	}
}

 

21、sync_rwmutex

package main

import (
	"fmt"
	"sync"
)

var sum int
var mutex sync.RWMutex

func Reader() {
	mutex.RLock() //读锁
	fmt.Printf("读到的是%d\n", sum)
	defer mutex.RUnlock() //释放读锁
}

func Write() {
	mutex.Lock()
	defer mutex.Unlock()
	sum += 2
}

func main() {
	for x := 0; x < 10; x++ {
		go Reader()
	}
	for x := 0; x < 10; x++ {
		go Write()
	}
	for x := 0; x < 10; x++ {
		go Write()
	}
}

 

package main

import (
	"fmt"
	"sync"
)

func main() {
	var num int
	var wg sync.WaitGroup
	var mutex sync.RWMutex
	go func() {
		defer wg.Done()
		mutex.Lock()
		num = 4
		mutex.Unlock()
		fmt.Printf("goroutine one, num=%d\n", num)
	}()

	go func() {
		defer wg.Done()
		mutex.Lock()
		num = 5
		mutex.Unlock()
		fmt.Printf("goroutine two, num=%d\n", num)
	}()

	wg.Add(2)
	wg.Wait()
	fmt.Println("end main goroutine")
}

 

package main

import (
	"fmt"
	"math/rand"
	"sync"
)

var count int
var rw sync.RWMutex

func main() {
	ch := make(chan struct{}, 6)
	for i := 0; i < 3; i++ {
		go ReadCount(i, ch)
	}
	for i := 0; i < 3; i++ {
		go WriteCount(i, ch)
	}
	for i := 0; i < 6; i++ {
		<-ch
	}
}
func ReadCount(n int, ch chan struct{}) {
	rw.RLock()
	fmt.Printf("goroutine %d 进入读操作...\n", n)
	v := count
	fmt.Printf("goroutine %d 读取结束,值为:%d\n", n, v)
	rw.RUnlock()
	ch <- struct{}{}
}
func WriteCount(n int, ch chan struct{}) {
	rw.Lock()
	fmt.Printf("goroutine %d 进入写操作...\n", n)
	v := rand.Intn(10)
	count = v
	fmt.Printf("goroutine %d 写入结束,新值为:%d\n", n, v)
	rw.Unlock()
	ch <- struct{}{}
}

 

package main

import (
	"sync"
	"time"
)

var m *sync.RWMutex

func main() {
	m = new(sync.RWMutex)
	// 多个同时读
	go Reading(1)
	go Reading(2)
	time.Sleep(2 * time.Second)
}
func Reading(i int) {
	println(i, "reading start")
	m.RLock()
	println(i, "reading")
	time.Sleep(1 * time.Second)
	m.RUnlock()
	println(i, "reading over")
}

 

package main

import (
	"sync"
	"time"
)

var m *sync.RWMutex

func main() {
	m = new(sync.RWMutex)
	// 写的时候啥也不能干
	go Writing(1)
	go Read(2)
	go Writing(3)
	time.Sleep(2 * time.Second)
}
func Read(i int) {
	println(i, "reading start")
	m.RLock()
	println(i, "reading")
	time.Sleep(1 * time.Second)
	m.RUnlock()
	println(i, "reading over")
}
func Writing(i int) {
	println(i, "writing start")
	m.Lock()
	println(i, "writing")
	time.Sleep(1 * time.Second)
	m.Unlock()
	println(i, "writing over")
}

 

22、sync_waitgroup

package main

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

func main() {
	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		defer wg.Done()
		fmt.Println("1 goroutine sleep ...")
		time.Sleep(2)
		fmt.Println("1 goroutine exit ...")
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		fmt.Println("2 goroutine sleep ...")
		time.Sleep(4)
		fmt.Println("2 goroutine exit ...")
	}()

	fmt.Println("Waiting for all goroutine ")
	wg.Wait()
	fmt.Println("All goroutines finished!")
}

 

package main

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

func main() {
	testFunc := func(wg *sync.WaitGroup, id int) {
		defer wg.Done()
		fmt.Printf("%v goroutine start ...\n", id)
		time.Sleep(2)
		fmt.Printf("%v goroutine exit ...\n", id)
	}

	var wg sync.WaitGroup
	const N = 3
	wg.Add(N)
	for i := 0; i < N; i++ {
		go testFunc(&wg, i)
	}

	fmt.Println("Waiting for all goroutine")
	wg.Wait()
	fmt.Println("All goroutines finished!")
}

 

23、timer

package main

import (
	"fmt"
	"time"
)

func Timer(duration time.Duration) chan bool {
	ch := make(chan bool)

	go func() {
		time.Sleep(duration)
		// 到时间啦
		ch <- true
	}()

	return ch

}

func main() {
	// 定时5秒
	timeout := Timer(5 * time.Second)

	for {
		select {
		case <-timeout:
			// 到时
			fmt.Println("already 5s!")
			//结束程序
			return
		}
	}
}

你好:我的2025