Go学习(九):并发编程2

【Golang学习之旅】Go 语言基础语法概览 ✅ 适合人群: Golang 新手 | 后端开发者 | 面试求职者✅ 文章亮点: 语法详解 + 实战代码 + 高质量示例✅ 目标: 10 分钟快速掌握 Golang 基础语法,助你高效写项目!Go 语言(Golang)是Google开发的一门静态强类型并发支持强语法简洁的编程语言,广泛应用于后端开发云计算微服务区块链等领域。🔹 Go 语言的 4 大核心特点:✅ 语法简洁(减少代码冗余,开发高效)✅ 高性能(比 Python 快,比 Java 简单) 阅读详情

目录

1、select

2、并发安全和锁(会涉及内核态和上下文切换,代价较高)

互斥锁

读写互斥锁

3、Sync实现同步

基本用法

sync.Once

4、原子操作(atomic包)(仅在用户态,代价比加锁低)

atomic包

5、GMP 原理与调度

 6、爬虫小案例


1、select

select关键字,可以同时响应多个通道的操作

select {
    case <-chan1:
       // 如果chan1成功读到数据,则进行该case处理语句
    case chan2 <- 1:
       // 如果成功向chan2写入数据,则进行该case处理语句
    default:
       // 如果上面都没有成功,则进入default处理流程
    }
package main

import (
	"fmt"
	"time"
)

func main() {
	// 创建2个管道
	int_chan := make(chan int, 1)
	string_chan := make(chan string, 1)
	go func() {
		//time.Sleep(2 * time.Second)
		int_chan <- 1
	}()
	go func() {
		string_chan <- "hello"
	}()

	//1、select可以同时监听一个或多个channel,直到其中一个channel ready
	//2、多个channel同时ready,则随机选择一个执行
	select {
	case value := <-int_chan:
		fmt.Println("int:", value)
	case value := <-string_chan:
		fmt.Println("string:", value)
	}
	//3、可以用于判断管道是否存满
	output3 := make(chan string, 10)
	go write(output3)
	//取数据,会一直运行下去
	for s := range output3 {
		fmt.Println("res:", s)
		time.Sleep(time.Second)
	}
}
func write(ch chan string) {
	for {
		select {
		// 写数据
		case ch <- "hello":
			fmt.Println("write hello")
		default:
			fmt.Println("channel full")
		}
		time.Sleep(time.Millisecond * 500)
	}
}

2、并发安全和锁(会涉及内核态和上下文切换,代价较高)

并发访问临界资源需要用到锁

互斥锁

var x int64
var wg sync.WaitGroup
var lock sync.Mutex

func add() {
    for i := 0; i < 5000; i++ {
        lock.Lock() // 加锁
        x = x + 1
        lock.Unlock() // 解锁
    }
    wg.Done()
}
func main() {
    wg.Add(2)
    go add()
    go add()
    wg.Wait()
    fmt.Println(x)
}

多个goroutine同时等待一个锁时,唤醒的策略是随机的

读写互斥锁

可以同时读,读时不可写,写时不可写不可读,适合读多写少的场景

var (
    x      int64
    wg     sync.WaitGroup
    lock   sync.Mutex
    rwlock sync.RWMutex
)

func write() {
    // lock.Lock()   // 加互斥锁
    rwlock.Lock() // 加写锁
    x = x + 1
    time.Sleep(10 * time.Millisecond) // 假设读操作耗时10毫秒
    rwlock.Unlock()                   // 解写锁
    // lock.Unlock()                     // 解互斥锁
    wg.Done()
}

func read() {
    // lock.Lock()                  // 加互斥锁
    rwlock.RLock()               // 加读锁
    time.Sleep(time.Millisecond) // 假设读操作耗时1毫秒
    rwlock.RUnlock()             // 解读锁
    // lock.Unlock()                // 解互斥锁
    wg.Done()
}

func main() {
    start := time.Now()
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go write()
    }

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go read()
    }

    wg.Wait()
    end := time.Now()
    fmt.Println(end.Sub(start))
}

3、Sync实现同步

基本用法

sync.WaitGroup是一个结构体,传递的时候要传递指针。

var wg sync.WaitGroup

func hello() {
    defer wg.Done()
    fmt.Println("Hello Goroutine!")
}
func main() {
    wg.Add(1)
    go hello() // 启动另外一个goroutine去执行hello函数
    fmt.Println("main goroutine done!")
    wg.Wait()
}

sync.Once

sync.Once其实内部包含一个互斥锁和一个布尔值,互斥锁保证布尔值和数据的安全,而布尔值用来记录初始化是否完成。这样设计就能保证初始化操作的时候是并发安全的并且初始化操作也不会被执行多次。

//用法:func (o *Once) Do(f func()) {}

var icons map[string]image.Image

var loadIconsOnce sync.Once

func loadIcons() {
    icons = map[string]image.Image{
        "left":  loadIcon("left.png"),
        "up":    loadIcon("up.png"),
        "right": loadIcon("right.png"),
        "down":  loadIcon("down.png"),
    }
}

// Icon 是并发安全的
func Icon(name string) image.Image {
    loadIconsOnce.Do(loadIcons)
    return icons[name]
}

Go语言中内置的map不是并发安全的

Go语言的sync包中提供了一个开箱即用的并发安全版map–sync.Map。开箱即用表示不用像内置的map一样使用make函数初始化就能直接使用。同时sync.Map内置了诸如Store、Load、LoadOrStore、Delete、Range等操作方法。

package main

import (
	"fmt"
	"strconv"
	"sync"
)

var m = sync.Map{}

func main() {
	wg := sync.WaitGroup{}
	for i := 0; i < 20; i++ {
		wg.Add(1)
		go func(n int) {
			key := strconv.Itoa(n)
			m.Store(key, n)
			value, _ := m.Load(key)
			fmt.Printf("k=:%v,v:=%v\n", key, value)
			wg.Done()
		}(i)
	}
	wg.Wait()
}

4、原子操作(atomic包)(仅在用户态,代价比加锁低)

atomic包

原子操作(atomic包) · Go语言中文文档 (topgoer.com)

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

var x int64
var l sync.Mutex
var wg sync.WaitGroup

// 普通版加函数
func add() {
	// x = x + 1
	x++ // 等价于上面的操作
	wg.Done()
}

// 互斥锁版加函数
func mutexAdd() {
	l.Lock()
	x++
	l.Unlock()
	wg.Done()
}

// 原子操作版加函数
func atomicAdd() {
	atomic.AddInt64(&x, 1)
	wg.Done()
}

func main() {
	start := time.Now()
	for i := 0; i < 10000; i++ {
		wg.Add(1)
		// go add()       // 普通版add函数 不是并发安全的
		// go mutexAdd() // 加锁版add函数 是并发安全的,但是加锁性能开销大	4.755ms
		go atomicAdd() // 原子操作版add函数 是并发安全,性能优于加锁版,	4.6828ms
	}
	wg.Wait()
	end := time.Now()
	fmt.Println(x)
	fmt.Println(end.Sub(start))
}

5、GMP 原理与调度

GMP 原理与调度 · Go语言中文文档 (topgoer.com)

 6、爬虫小案例

案例:并发下载图片第5页 | 必应每日高清壁纸 - 精彩,从这里开始 (ioliu.cn)

没实现图片的下载,发现找到的路径不是下载路径,放弃了,大概是这么个意思

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"

	"strconv"
	"strings"
	"sync"
	"time"

	htmlquery "github.com/antchfx/htmlquery"
)

var wg sync.WaitGroup
var wgd sync.WaitGroup

// 存放图片链接的数据管道
var chanImageUrls chan string

//并发爬取壁纸
//https://bing.ioliu.cn/?p=1

func HandleError(err error, why string) {
	if err != nil {
		fmt.Println(why, err)
	}
}

func getImgUrls(url string) {
	defer wg.Done()

	//爬取每一页的图片链接
	urls := getImgs(url)

	//遍历切片里所有链接,存入数据管道
	for _, url := range urls {
		chanImageUrls <- url
	}
	fmt.Printf("%s 完成了爬取任务\n", url)
}
func getImgs(url string) (urls []string) {
	pageStr := getPage(url)
	//1、使用正则匹配
	//<a class="mark" href="/photo/AstoriaBridge_ZH-CN5052905610?force=home_2"></a>
	var reImg = `"/photo/(.*?)"`
	re := regexp.MustCompile(reImg)
	results := re.FindAllString(pageStr, -1)
	baseurl := "https://bing.ioliu.cn"
	//不知道为什么匹配结果都带“”,不应该只出现()里的内容吗??
	for _, result := range results {
		//fmt.Println(i, result)
		urls = append(urls, baseurl+result[1:len(result)-1])
	}
	//fmt.Println(urls)
	return
}
func getImgsXpath(url string) {
	//2、使用xpath匹配
	//go get github.com/antchfx/htmlquery
	resp, err := htmlquery.LoadURL(url) //Load HTML document from URL.
	HandleError(err, "htmlquery.LoadURL")
	//defer resp.Body.Close()	//怎么关闭
	results := htmlquery.Find(resp, "/html/body/div[3]/div/div/a[@href]")
	for _, n := range results {
		fmt.Println(htmlquery.SelectAttr(n, "href")) // output @href value
	}

}

func getPage(url string) (pageStr string) {
	resp, err := http.Get(url)
	HandleError(err, "http.Get url")
	defer resp.Body.Close()
	pageBytes, err := ioutil.ReadAll(resp.Body)
	HandleError(err, "ioutil.ReadAll")
	pageStr = string(pageBytes)
	return pageStr

}

func DownloadImg() {
	defer wgd.Done()
	for url := range chanImageUrls {
		filename := GetFilenameFromUrl(url)
		ok := DownloadFile(url, filename)
		if ok {
			fmt.Printf("%s 下载成功\n", filename)
		} else {
			fmt.Printf("%s 下载失败\n", filename)
		}
	}
}

// 下载图片保存的名字
func GetFilenameFromUrl(url string) (filename string) {
	// 返回最后一个/的位置
	lastIndex := strings.LastIndex(url, "/")
	// 切出来
	filename = url[lastIndex+1:]
	// 时间戳解决重名
	timePrefix := strconv.Itoa(int(time.Now().UnixNano()))
	filename = timePrefix + "_" + filename
	return
}

// 下载图片
func DownloadFile(url string, filename string) (ok bool) {
	resp, err := http.Get(url)
	HandleError(err, "http.get.url")
	defer resp.Body.Close()
	bytes, err := ioutil.ReadAll(resp.Body)
	HandleError(err, "resp.body")
	filename = "D:/tempdownforgo/img/" + filename
	// 写出数据
	err = ioutil.WriteFile(filename, bytes, 0666)
	if err != nil {
		fmt.Println(url)
		return false
	} else {
		return true
	}
}
func main() {
	//1、测试爬取
	// pageStr := getPage("https://bing.ioliu.cn/?p=1")
	// fmt.Println(pageStr)
	// getImgs("https://bing.ioliu.cn/?p=1")
	// getImgsXpath("https://bing.ioliu.cn/?p=2")

	//1、初始化管道
	chanImageUrls = make(chan string, 1000)

	// 2、并发爬取
	for i := 1; i < 5; i++ {
		wg.Add(1)
		go getImgUrls("https://bing.ioliu.cn/?p=" + strconv.Itoa(i))
	}
	wg.Wait()
	//3、并发下载
	for i := 0; i < 3; i++ {
		wgd.Add(1)
		go DownloadImg()
	}
	wgd.Wait()
}
Go 学习笔记 · 进阶篇 · 第二天:并发编程深度实践 Go 的并发是轻量高效的,Goroutine 比线程香。Channel 是 goroutine 之间的传声筒。WaitGroup、Mutex、Context 是并发控制的三剑客。并发编程容易埋雷,写完一定记得加-race运行!今日咒语:“人生苦短,让 goroutine 去忙,主程序才轻松。 阅读详情

相关推荐

76、Go并发编程实战:从基础到实战案例解析

本文通过实战案例,深入浅出地介绍了Go语言的并发编程特性。从基础的goroutine和channel,到生产者消费者模型,再到Web服务器和并发爬虫,以及并发排序,全方位展示了Go在并发编程方面的优势和应用。同时,文中还提到了一些实用技巧和最佳实践,帮助读者更好地理解和应用Go的并发编程。

silenceallat的博客 1847

100天精通Golang(基础入门篇)——第1天:学习Go语言基本概念

100天精通Golang(基础入门篇)——第1天:学习Go语言基本概念,欢迎来到100天精通Golang的基础入门篇!在这个系列教程中,我们将带领你逐步掌握Go语言的核心概念和语法。本篇博文将着重介绍Go语言的基本概念,包括其定义、用途和优势。通过阅读本文,你将对Go语言有一个清晰的了解。在第1天的学习中,我们将探索Go语言的基本概念。我们将介绍Go语言是什么,它可以用来做什么,以及它相较于其他编程语言的优势。

猫头虎技术团队:授渔优于赠鱼,兴趣引领智慧,探索之乐尤显珍贵。商务合作+:Libin9iOak ,万粉变现+:优快云WF,猫头虎承诺每年免费为100名C站创作者做账号流量诊断服务!全网搜:猫头虎技术团队,点击文章底部名片或直接私信我一切皆可谈,快找虎哥! 6万+

Golang go routine调度器:让并发编程更简单高效

Golang(Go)的并发模型以goroutine和channel为核心,而调度器作为goroutine运行的底层引擎,直接影响程序的并发性能和资源利用率。解析调度器的核心架构(GMP模型)和调度策略揭示调度器如何实现轻量级线程的高效管理演示调度器在实际项目中的应用和优化方法覆盖内容包括调度器原理、算法实现、数学建模、实战案例和工具推荐,适用于希望深入理解Go并发机制的开发者。背景介绍:定义目标、读者和术语核心概念:解析GMP模型及调度器架构算法原理:工作窃取、抢占调度等核心算法数学模型。

AI Agent Harness Engineering 1003

[GO语言基础] 一.为什么我要学习Golang以及GO语言入门普及

作为网络安全初学者,会遇到采用Go语言开发的恶意样本。因此从今天开始从零讲解Golang编程语言,一方面是督促自己不断前行且学习新知识;另一方面是分享与读者,希望大家一起进步。这系列文章入门部分将参考“尚硅谷”韩顺平老师的视频和书籍《GO高级编程》,详见参考文献,并结合作者多年的编程经验进行学习和丰富,且看且珍惜吧!后续会结合网络安全进行GO语言实战深入,驾驭~ 这些年我学过各种编程语言,从最早的C语言到C++,再到C#、PHP、JAVA,再到IOS开发、Python,到最新的GO语言,学得是真的杂。有时

杨秀璋的专栏 12万+

分享2024 golang学习路线

Go语言(也称为Golang)是Google开发的一种静态强类型、编译型语言,它具有简洁、快速、安全、并发等特点,尤其适合构建大型软件、微服务架构和云平台服务。Go的学习曲线相对平缓,社区活跃,是现代编程语言中的佼佼者。下面为您提供2024年的Golang学习路线,供您参考。Golang的学习路线从基础到高级应用有一个明确的路径,重点在于理解其并发模型和标准库的强大功能。实践是最好的学习方式,不断编写代码,解决实际问题,可以帮助你更深入地理解Go语言的特性和优势。

青玉白露的博客 2882

基于奥比中光Orbbec Astra Pro与ROS实现实时3D环境建模:orb_slam2实战指南

本文提供了一份详细的实战指南,介绍如何使用奥比中光Orbbec Astra Pro深度摄像头与ROS系统,部署并运行ORB-SLAM2算法,实现实时3D环境建模与定位。内容涵盖从驱动安装、环境配置、算法编译到摄像头标定与性能调优的全流程,旨在帮助开发者快速搭建一套高性价比的视觉SLAM系统。

weixin_29054399的博客 334

Go-Golang学习总结笔记

资源 某hub会审核不通过,自己去找吧 书籍 网站 基础 go官方中文网 菜鸟教程 C语言网 go语言中文网 golang系列 视频 基础 安装 依赖管理 数据类型 变量和常量 流程控制 函数 包 面向对象编程 提高 ...

关注网络安全、云原生安全 2万+

大模型学习路线之多模态模型

​ (Frankly speaking,博主太懒了)章节一只对CLIP、BLIP、BLIP2、InstructBLIP进行了整理,章节二以CLIP、VisualGLM作为实践案例。​ 实际上多模态模型除了CLIP、BLIP、BLIP2、InstructBLIP,还有LLaVA、miniGPT4,以及国内清华的VisualGLM、阿里的Qwen-VL等。(更多多模态原理可以看文末的参考说明)一、多模态模型 & 理论。

2401_86435672的博客 2287

Golang的学习路线

Golang的学习路线

Mr_XiMu的博客 9501

XianYuAutoDeliveryX:基于闲鱼API与大模型的智能自动发货系统实践

本文详细介绍了如何利用XianYuAutoDeliveryX系统,结合闲鱼API与大语言模型,构建一个智能自动发货解决方案。该系统能实现买家付款后秒级自动发货,并通过对接ChatGPT等大模型智能回复买家咨询,有效解放卖家时间,提升虚拟商品店铺的运营效率和客户体验。

bush的博客 1015

使用ST-LINK烧录stm32教程说明

使用ST-LINK烧录stm32

qq_34426854的博客 1万+

golang学习九:Go并发编程

一、概述: 所谓并发编程是指在一台处理器上“同时”处理多个任务; 宏观的并发是指在一段时间内, 有多个程序在同时运行; 并发在微观上, 是指在同一时刻只能有一条指令执行, 但多个程序指令被快速的轮换执行, 使得在宏观上具有多个进程同时执行的效果, 但在微观上并不是同时执行的, 只是把时间分成若干段, 使多个程序快速交替的执行; 1. 并行与并发: 并行(parallel): 指在同一时刻, 有多条指令在多个处理器上同时执行; 并发(concurrency)L指在同一时刻只能有一条指令执行, 但多个进程指

浅弋、璃鱼的博客 903

【汽车ECU电控数据管理篇】A2L文件在ECU标定中的关键作用与实战解析

本文深入解析A2L文件在汽车ECU标定中的关键作用,详细介绍了其作为'数据字典'的核心功能与实战应用。通过剖析A2L文件的结构、关键标签及常见问题,帮助工程师高效管理电控数据,提升ECU标定效率与准确性。文章特别强调了ASAP2标准下的A2L文件在汽车电控系统中的重要性。

a3b4c5的博客 787

从Java到Go:Java工程师的Golang学习指南

作为一名Java工程师,你可能已经习惯了Java的面向对象编程、强大的生态系统以及丰富的工具链。然而,随着Go语言(Golang)在云计算、微服务和并发编程领域的崛起,学习Go语言成为了一个非常有价值的选择。本文将通过对比Java和Go语言的方式,帮助你快速掌握Go语言的核心概念,并通过详细的案例讲解,帮助你理解两者之间的异同。 Go 对比: Go 对比: Go 对比: Go 对比:Java通过类和接口实现多线程编程,或者使用包中的高级并发工具。 Go Go语言通过实现并发,是轻量级的线程,由Go运

SunnyRivers 1751

别再混淆了!深入浅出图解四元数姿态控制中的‘误差四元数’(附四种定义对比与仿真)

本文深入解析四元数姿态控制中的误差四元数定义差异,对比四种常见定义(如Q₀∘Q⁻¹与Q⁻¹∘Q₀)及其对PD控制性能的影响。通过刚体动力学仿真验证,揭示定义二(Q⁻¹∘Q₀)在无人机和航天器控制中的最优性能,提供工程实践建议与参数整定技巧,帮助开发者避免常见陷阱并提升控制效率。

weixin_42528191的博客 277

python全栈入门到实战【基础篇 01】Python初识:定位、优势与发展历程

本文介绍了热门编程语言Python。它是解释型高级语言,具通用、入门友好、胶水型特点,以简洁易读为设计哲学。优势包括语法简洁高效、生态庞大、跨平台、社区活跃、应用广泛、门槛低。发展历经诞生(1989-1994,吉多创建,1994年1.0发布)、成长(版本迭代,3.0发布)、崛起(Web与大数据推动)、爆发(AI浪潮助推)及持续迭代阶段。

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 1万+

golang调用webview,webview2,go-webview2

golang调用webview,webview2,go-webview2

猛犸象 3119

C# MVVM的“核武器”:CommunityToolkit.Mvvm的RelayCommand实战全解

你默默打开VS:“该用RelayCommand的‘量子纠缠’魔法了!用户点击按钮无响应,调试器显示命令未绑定,但代码看起来完美无缺。“我的MVVM应用?那可是能穿越线程的命令量子计算机!异步操作阻塞了UI线程,用户界面变成“加载中”死循环。:UI与业务逻辑通过命令“量子隧道”解耦。:所有长时间操作自动进入“量子跃迁”模式。:携带任意上下文的“量子信封”传递。:命令可用性随数据变化实时同步。

java专栏 663

Java转Go:java开发者转学go语言,请给我一些建议和学习推荐

在做开发时遇到最无理的需求就是部门没了😂

鄙人kunzhi96,感恩遇见! 8065

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【golang学习之旅】Go 语言并发编程(goroutine、channel 的使用)

✅ 适合人群:Golang 开发者 | 并发编程初学者 | 后端开发工程师✅ 文章亮点:深入解析 Goroutine & Channel + 代码示例 + 实战场景✅ 目标:掌握 Go 并发编程核心,让你的代码更高效、更强大!Goroutine是Go语言的轻量级线程,由Go运行时管理,而非操作系统。相比传统线程,Goroutine占用内存小:默认仅2KB栈空间,可动态扩展调度高效:Go运行时管理Goroutine的调度,无需手动创建线程启动成本低:创建Goroutine比创建线程的开销小很多。

程序员林北北的博客 1252

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

golang学习线路图

golang学习线路图

gopher123的博客 2825

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Golang基础7-并发编程

Golang基础-并发编程

m0_61973596的博客 1550

Golang如何简化并发编程?

Go语言通过其独特的并发模型和简洁的语法大大简化了并发编程的复杂性。通过使用轻量级的goroutines和直观的channels通信机制,开发者可以更加高效地处理并发任务,从而提高应用的性能和响应速度。然而,在使用Go语言的并发特性时,也需要注意一些关键点,如避免死锁、控制goroutine的数量以及优雅地关闭goroutines等。通过遵循这些注意事项和最佳实践,开发者可以更加高效地利用Go语言的并发优势来构建高性能、高可用的应用。来自:33066.cn/gonglue/163.html。

PrimoRosal的博客 1799

Go 和 Golang 有什么关系?

大家好,我是煎鱼。最近天气也冷了,掐指一算是招聘季了,无论是校招、社招、HR、面试官们都蠢蠢欲动。这不,我有一个朋友的 HR 朋友都有起名困难了,一看 Go 语言的工作说明(Job Des...

EDDYCJY的博客 1万+

聊聊并发编程,另送5本Golang并发编程新书

大家好,我是飞哥!并发编程并不是一个新话题,但是我觉得在近几年以及未来的时间里,并发编程将显得越来越重要。为什么这样讲,让我们先回到一个基本的问题上来,为什么我们要采用并发编程?关于这个问题可能会有多种答案,但是最根本的答案是受 CPU 硬件发展的影响。摩尔定律原意说的是每隔 18 个月处理器的速度会翻一翻。从 1970 年到 2002 年的这段时间里,硬件确实大致是按照这个规律发展的。但是进入到...

zhangyanfei01的专栏 1372

Golang 生态学习

虽然 Go 在人工智能领域不如 Python 那样流行,但由于其出色的性能和并发支持,Go 也开始被用于一些 AI 和机器学习(ML)项目,尤其是对于需要高并发、高性能的任务,Go 可以提供优势。• 《Go语言圣经》(The Go Programming Language):这是学习 Go 语言的经典书籍,涵盖了 Go 的所有基础内容。它被广泛应用于供应链、金融等行业的区块链解决方案。:Go 的并发模型(goroutines 和 channels)是 Go 的强项,学习并发编程是使用 Go 的重要步骤。

A_Tevens的博客 1515
上一篇: Go学习(八):并发编程1
下一篇: VMware部署K8s
Lay_XZ
博客等级 码龄5年 29粉丝 14原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值