标签 goroutine 下的文章

AWS 大神发文炮轰:Go 的并发就是个“笑话”,JVM 的方案要更优越

本文永久链接 – https://tonybai.com/2026/05/07/aws-guru-slams-go-concurrency-as-a-joke-vs-jvm

大家好,我是Tony Bai。

过去十年,如果要在后端技术圈选出一个“金字招牌”,那无疑是 Go 语言的并发

凭借其极简的 go 关键字和优雅的 channel,Go 将并发编程的门槛从“博士级”拉到了“入门级”。在云原生和微服务的浪潮中,Go 几乎就是“高并发”的代名词。

但就在前几天,AWS 的资深布道师 James Ward,在 X 平台上突然向 Go 语言的这个“优势高地”发起了猛烈炮轰:

“开发者普遍认为 Go 在并发方面很出色。但事实并非如此。JVM 的方案要优越得多。当你把虚拟线程、结构化并发和 Effects 加进来时,它甚至是全行业最好的方案之一。”

为了证明自己的观点,他还引用了前 Google 工程师 Ahmetb(以其在 K8s 社区的贡献而闻名)设计的一道极其刁钻的并发编程“考题”——实现一个工业级的、线程安全的网络连接池

这道题,像一块试金石,炸出了 Go 并发模型背后那些被“易用性”所掩盖的无数“天坑”。

这场由大神发起的“语言战争”,瞬间引爆了技术圈。从前 Uber 工程师到 Victoria Metrics 的核心开发者,无数 Gopher 下场“护驾”。

今天,我们就来复盘这场神仙打架,看看当 Go 的“平民法拉利”遭遇现代 JVM 的“德系重装甲”时,到底谁才是真正的并发之王?

战火的点燃:一道价值千金的“并发考题”

让我们先来看看点燃这场战争的导火索,Ahmetb 设计的这道“连接池”考题:

你需要实现一个线程安全的、有界连接池。
1. Acquire():当池中无可用连接时,必须阻塞。必须响应 context 的超时和取消。
2. Release():归还连接。如果池已满或连接已损坏,则关闭连接而不是泄漏。
3. Close():必须干净利落地关闭整个池。停止接受新请求,立即关闭所有空闲连接,并等待所有正在被使用的连接被归还后,再关闭它们
4. IdleTimeout:自动清理超过空闲时长的连接。

这道题,看似简单,实则布满了“杀机”。

它几乎涵盖了并发编程中所有最令人头疼的场景:资源限制、优雅启停、生命周期管理、超时与取消、后台清理……

Ahmetb 坦言:

“如果你享受 Go 的并发原语,那就挑战一下自己去实现它。这里面的边缘情况,比我最初想象的要多得多。”

而 James Ward 正是借着这道题,打出了他的第一炮:用 Go 的原生 channel 和 select 去完美地解决所有这些问题,其代码量和心智负担,将远超现代 JVM 的解决方案。

两派的交锋:Go 的“野路子” vs JVM 的“正规军”

面对 James 的炮轰,评论区迅速分裂成两大阵营。

Go 阵营(以实战派为首)的反击:

前 Uber 工程师 Ovais Tariq 现身说法:

“Go 在高并发工作负载下更优越——这是我在 Uber 运营大规模 Go 服务的实践经验。”

另一位开发者则指出了 Go 的核心优势:

“我完全同意(Go 更优)。这个工具(Go)被创造出来,就是为了无缝处理成千上万个大部分时间都在‘等待’I/O 的任务。在这个角色上,Go 至今仍然表现卓越。”

Go 阵营的核心观点是:Go 的并发模型(Goroutine + Channel),就像一把简单、锋利的匕首。它足够轻、足够快,虽然需要使用者自己具备高超的技巧,但在真实的、海量的 I/O 密集型场景下,它的实战表现就是最好的证明。

JVM 阵营(以理论派为首)的降维打击:

James Ward 则对这些“实践经验”嗤之以鼻:

“真的吗?像 Scala ZIO 这样的 Effect 调度器和虚拟线程,在安全处理非阻塞任务时,看起来比 Goroutine 要容易得多。”

JVM 阵营的核心观点是:Go 的并发原语太“低级”了。 它把所有关于取消、超时、错误传播、资源清理的复杂性,全部甩给了开发者。而现代 JVM 生态,通过虚拟线程结构化并发(Structured Concurrency)函数式 Effect 系统(如 ZIO, Arrow Fx),已经从语言和框架层面,为你提供了一套“三位一体”的、体系化的解决方案。

  • 虚拟线程:让 JVM 拥有了和 Goroutine 一样廉价的“百万级”并发能力。
  • 结构化并发:强制所有并发任务拥有清晰的父子关系和生命周期,彻底消灭“野 Goroutine”和资源泄漏。
  • Effect 系统:用类型系统来管理异步任务的副作用,让并发代码像写同步代码一样清晰和安全。

这场争论的本质,是“游击队”与“正规军”的对决。Go 提供了最灵活的单兵作战武器,而 JVM 则提供了一整套陆海空协同作战的军事体系。

Go 的“平民化”哲学 vs JVM 的“专家级”哲学

在这场混乱的口水战中,Victoria Metrics 的工程师 Phuong Le 的一篇复盘长文,将整个讨论提升到了哲学的高度。

他没有去争论谁快谁慢,而是深刻地剖析了两种技术路线背后的设计哲学差异

“Go 在并发方面并不差。一个更真实的说法是:Go 擅长让并发变得廉价、显式和易于上手,尤其是在常见的后端模式中。”

Phuong Le 指出,Go 的核心优势在于“平民化(Approachable)”

它用极其简单的原语,让一个普通的开发者,也能快速地写出“看起来能用”的并发代码。但这种“简单”的代价是,它把大量的“正确性”责任,下放给了开发者自己。

“Go 给了你相对低级的原语。大量关于取消、任务生命周期、清理、错误传播和背压的正确性保证,都留给了我们程序员自己去处理。”

而现代 JVM 生态,则走向了另一个极端——“专家系统”

它试图在框架和语言层面,构建一个极其复杂、但理论上绝对安全的“象牙塔”。开发者需要学习大量的概念(Monad, Functor, Fiber…),但一旦学会,就能获得极高的安全性保障。

Phuong Le 的结论是:

“所以,公平的比较不是‘Go vs JVM,谁赢?’,而是:Go 优化的是简单的、实用的并发;而现代 JVM 生态,拥有更强大的工具来处理结构化的、资源安全的并发。 到底哪个更好,取决于你面临的并发问题有多复杂。”

你的团队,需要匕首还是航母?

这场神仙打架,最终没有赢家。但它为我们所有后端架构师,提供了一次极其宝贵的“架构选型”公开课。

1. 承认 Go 的“天花板”

我们必须承认,Go 的原生并发原语,在处理极其复杂的、需要精细化资源管理的场景时,确实存在“天花板”。Ahmetb 的那道“连接池”考题,就是一个完美的试金石。如果你团队的业务复杂到这种程度,直接引入一个成熟的第三方库(或者评估 JVM 生态),可能比自己手搓 Channel 要明智得多。

2. 警惕 JVM 的“学习曲线”

虚拟线程虽然抹平了 JVM 在并发“数量”上与 Go 的差距,但结构化并发和 Effect 系统,依然是较为陡峭的学习曲线。在一个追求快速迭代、人员流动频繁的团队里,引入这些“重型武器”的培训成本和心智负担,是必须被严肃评估的。(注:不知道有多少Java开发至今也没有使用过虚拟线程)

3. “足够好”也许就是最好的

评论区里,Jacob Voytko 的观点极具代表性:

“Go 的并发原语并非在所有方面都理想,但对于终端用户(业务开发者)大多数时候写的那些东西来说,它们是完美的。管理 fan-in/fan-out、处理带超时的异步任务……对于这些 80% 的场景,Go 的‘足够好’方案已经足够了。”

小结:没有银弹,只有权衡

这场由 James Ward 发起的“Go 并发之战”,最终以一场关于“架构权衡(Trade-offs)”的深刻反思而告终。

它像一面镜子,照出了我们这个行业最真实的底色:从来没有“最好的”语言,只有“最适合的”场景。

Go 的成功,在于它用最简单的武器,解决了云原生时代最大多数的并发问题。它的哲学,是牺牲一部分理论上的“完美”,去换取工程上的“极致效率”。

而现代 JVM 的进化,则代表了另一种可能:通过不断叠加更高级的抽象,去追求一个理论上“绝对安全”的并发乌托邦。

作为架构师,我们的终极使命,不是去争论哪条路更高贵,而是在理解了所有路径的代价之后,为我们的团队、我们的业务,选择那条最务实的、能活着走到终点的路。

资料链接:

  • https://x.com/JamesWard/status/2049498133013344285
  • https://x.com/func25/status/2050243999123009662
  • https://x.com/ahmetb/status/2049341220707844340

今日互动探讨:

你如何看待 James Ward“Go 并发不行”的观点?在你的实战中,Goroutine+Channel 是否真的“够用”?或者你更期待 Go 能引入类似 JVM 的“结构化并发”?

欢迎在评论区分享你的看法!


还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 从0 开始构建 Agent Harness 将带你:

  • 抛弃臃肿框架,回归“驾驭工程 (Harness Engineering)”的第一性原理
  • 用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等,复刻极简OpenClaw
  • 构建坚不可摧的 Safety Middleware 与飞书人工审批防线
  • 在底层实现 Token 成本审计、链路追踪与自动化跑分评估
  • 从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”

扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。


原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!

我们致力于打造一个高品质的 Go 语言深度学习AI 应用探索 平台。在这里,你将获得:

  • 体系化 Go 核心进阶内容: 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏,夯实你的 Go 内功。
  • 前沿 Go+AI 实战赋能: 紧跟时代步伐,学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等,掌握 AI 时代新技能。
  • 星主 Tony Bai 亲自答疑: 遇到难题?星主第一时间为你深度解析,扫清学习障碍。
  • 高活跃 Gopher 交流圈: 与众多优秀 Gopher 分享心得、讨论技术,碰撞思想火花。
  • 独家资源与内容首发: 技术文章、课程更新、精选资源,第一时间触达。

衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

img{512x368}


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

为什么说 go 语句是新时代的 goto?四大法则拯救失控 goroutine

本文永久链接 – https://tonybai.com/2026/04/16/structured-concurrency-in-go-research-oriented-perspective

大家好,我是Tony Bai。

Go 语言的 go 关键字是并发编程史上的一次民主化革命,它让并发变得前所未有的廉价和简单。只需在一个函数调用前加上 go,我们就拥有了一个并发执行的任务。

这种语法是如此的诱人,以至于新手 Gopher 往往会沉迷于创建成千上万个 Goroutine。

随着 Go 语言步入第 16 个年头,学术界和工程界也开始重新审视这种“极简主义”带来的副作用。

2025 年 3 月,一篇发表在《Scientific Research Journal》上的重磅论文《Structured Concurrency in Go: A Research-Oriented Perspective》,将 Go 的并发模型与 1968 年 Dijkstra 对 Goto 语句的批判联系了起来。

论文作者 Georgii Kliukovkin 指出,这种“发射后不管(Fire-and-Forget)”的模式,虽然在 Hello World 级别的程序中运行良好,但在大规模分布式系统中,它是资源泄漏、死锁和竞态条件的温床。

我们日常也常听到这样的抱怨:“Go 的并发很简单,但写出正确的并发代码很难。” 这并非语言本身的缺陷,而是因为我们缺乏一种与语言灵活性相匹配的约束纪律。这种纪律,就是结构化并发

本文将深入解读这篇论文,探讨为何“不受限制的 Goroutine”正在成为新时代的“Goto 语句”,以及我们如何通过结构化并发(Structured Concurrency)的四大法则,将失控的协程重新关回笼子,构建坚如磐石的系统。

历史的镜像——从 Goto 有害论到 Goroutine 有害论?

要理解“结构化并发”,我们必须先回顾历史。

1968年的呼喊:结构化编程的诞生

在 20 世纪 60 年代,编程界流行的是“非结构化编程”。开发者可以随心所欲地使用 goto 语句在代码的任意位置跳转。这种自由带来了极大的灵活性,但也导致了所谓的“意大利面条代码(Spaghetti Code)”——控制流杂乱无章,难以追踪程序的执行路径,维护简直是噩梦。

1968 年,图灵奖得主 Edsger W. Dijkstra 发表了那篇著名的《Go To Statement Considered Harmful》(Goto 语句有害论)。他主张废除无限制的跳转,转而使用结构化编程(Structured Programming):即所有的逻辑都应由顺序结构、选择结构(if/else)和循环结构(for/while)以及函数调用(Function Call)组成。

结构化编程的核心价值在于“黑盒化”。当你调用一个函数时,你确信控制权最终会回到你手中(除非死循环或崩溃);你确信该函数内部的变量不会污染外部环境。这种“入口-出口”的对称性,是软件可维护性的基石。

2025年的回响:go 语句 即 Goto

论文提出了一个让人振聋发聩的观点:Go 语言中的 go 语句,在某种意义上,就是并发领域的 goto。

当你执行 go func() 时,你实际上是启动了一个新的执行流,它跳出了当前的词法作用域(Lexical Scope)。

  • 它什么时候开始?不确定。
  • 它什么时候结束?不知道。
  • 它如果 Panic 了会怎样?可能会炸掉整个程序。
  • 父函数返回了,它还在运行吗?很有可能。

这种“射后不理(Fire-and-Forget)”的模式,破坏了代码的封装性。就像当年的 goto 打破了控制流的结构一样,不受约束的 go 语句打破了并发流的结构。

结构化并发的目标,就是要把这些“野生”的 Goroutine 重新关进“代码块”的笼子里,让并发程序的生命周期像同步程序一样清晰、可预测。

打破幻象——Go 并发的三个误区

在引入解决方案之前,论文首先抨击了 Go 社区中常见的三个关于并发的迷思。这些误区往往是导致系统不稳定的根源。

误区 1:“Goroutine 极度廉价,所以可以随便开”

是的,Goroutine 的初始栈只有 2KB,但这只是“内存”成本。从“生命周期”的角度看,一个泄露的 Goroutine 是极其昂贵的。

如果不加控制地启动 Goroutine 而不确保其退出,这些“孤儿”协程可能会:

  • 持有数据库连接或文件句柄不释放。
  • 阻塞在某个永远不会发送数据的 Channel 上。
  • 阻止垃圾回收器(GC)回收其引用的对象。

在长期运行的服务中,这种微小的泄漏会像滚雪球一样,最终导致服务 OOM(内存溢出)。

误区 2:“Channel 解决了所有同步问题”

Rob Pike 的名言“不要通过共享内存来通信,要通过通信来共享内存”被许多人奉为圭臬。然而,Channel 并不是银弹。

Channel 实际上引入了复杂的状态机问题:

  • 向已关闭的 Channel 发送数据会 Panic。
  • 从 nil Channel 读取会永久阻塞。
  • 无缓冲 Channel 容易导致死锁。
  • 过多的 Channel 会导致逻辑碎片化,增加认知负担。

论文强调,Channel 是一种传输机制,而不是一种架构保障。没有设计良好的生命周期管理,Channel 只会让 Bug 变得更难调试。

误区 3:“Go 的并发代码很容易测试”

Go 提供了 go test -race,但这远远不够。并发 Bug 往往是非确定性的(Heisenbugs),在本地开发环境(低负载、少核)下可能永远不会出现,一上生产环境(高负载、多核)就崩溃。

如果代码缺乏结构化,测试将变得极其困难。你无法确定在断言(Assert)的那一刻,后台的 Goroutine 是否已经完成了数据的写入。结构化并发通过明确的“等待”机制,能让并发测试变得像同步测试一样稳定。

核心法则——构建坚固的并发大厦

既然 Go 语言层面(目前)没有强制的结构化并发语法(不同于 Java Project Loom 的 StructuredTaskScope 或 Python Trio 的 Nursery),我们需要依靠工程纪律和设计模式来实现它。论文详细阐述了四大核心法则。

法则一:Scope 闭环原则 —— 在谁的 Scope 启动,就在谁的 Scope 等待

定义任何启动 Goroutine 的函数,必须负责等待它们结束。

这是结构化并发的第一天条。绝不允许 Goroutine 的生命周期“逃逸”出启动它的函数。这保证了当函数返回时,它所衍生的所有并发工作都已完结,资源已释放。

❌ 反模式:泄露的抽象

// 这是一个危险的模式:函数返回了,但后台任务还在跑
// 调用者无法知道任务何时完成,也无法处理 panic
func FireAndForget() {
    go func() {
        // 执行一些可能会阻塞很久的任务
        // 这里发生的一切,父函数都无法控制
    }()
}

✅ 正模式:Wait 优于 Sleep

论文强烈建议使用 sync.WaitGroup 或 errgroup 来显式地界定生命周期边界。

func ProcessStructured(items []Data) {
    var wg sync.WaitGroup

    for _, item := range items {
        wg.Add(1)
        // 使用闭包捕获变量时需注意
        go func(val Data) {
            defer wg.Done()
            process(val)
        }(item)
    }

    // 关键点:在函数返回前,必须收敛所有并发流
    // 这形成了一个清晰的“并发块”
    wg.Wait()
}

通过这种方式,ProcessStructured 函数的行为变成了“同步”的黑盒。调用者不需要知道它内部是否使用了并发,只需要知道“当函数返回时,所有工作都已完成”。

法则二:同步外观原则 —— API 应当表现为“同步”

定义即使函数内部使用了高并发,对外暴露的 API 签名应当是同步阻塞的。

这是一个看似反直觉的建议。既然我们写的是并发程序,为什么 API 要设计成同步的?

论文指出,异步 API(如返回一个 <-chan Result 或 Future)具有“传染性”。一旦你的函数返回了一个 Future,调用者就必须处理这个 Future 的等待逻辑,这会层层向上传递,导致整个调用链都充满了并发管理的细节。

经典案例:http.ListenAndServe

Go 标准库的 http.ListenAndServe(“:8080″, nil) 是结构化并发 API 设计的典范。

  • 内部:它是一个极其复杂的并发系统,为每个进来的 TCP 连接启动一个新的 Goroutine。
  • 外部:它是一个简单的阻塞函数。
// 调用者代码
err := http.ListenAndServe(":8080", nil)

// 当这行代码返回时,我们确切地知道:
// 1. 服务已经停止了。
// 2. 或者发生了错误(如端口冲突)。

如果 ListenAndServe 被设计成异步返回(即在后台启动服务后立即返回),那么调用者将面临巨大的困扰:我该如何知道服务启动成功了?如果启动失败,错误去哪里了?主进程该何时退出?

除非是专门的任务调度器,否则业务逻辑函数的 API 应该看起来是同步阻塞的。让调用者去决定是否使用 go 关键字来调用它。

法则三:所有权原则 —— 在哪写入,就在哪关闭

定义只有负责向 Channel 写入数据的 Goroutine,才有资格关闭该 Channel。

Channel 的关闭操作是 Go 并发中最容易导致 Panic 的环节(向已关闭的 Channel 发送数据)。论文强调,结构化并发可以极大地简化 Channel 的管理。

原则非常简单:谁生产,谁负责清理。 接收者(Consumer)永远不应该关闭 Channel,因为通过关闭 Channel 来通知生产者“我读完了”是一种错误的设计(应该使用 Context 来取消)。

结合法则一,如果生产者 Goroutine 的生命周期是受控的,那么 Channel 的生命周期自然也是受控的。

func Producer() <-chan int {
    ch := make(chan int)

    // 启动生产者协程
    go func() {
        // defer close 确保无论正常退出还是 panic,channel 都会关闭
        // 避免接收者永久阻塞
        defer close(ch) 

        for i := 0; i < 10; i++ {
            ch <- i
        }
    }()

    return ch
}

法则四:物理封装原则 —— 数据与锁不分家

定义将共享的可变数据(Mutable State)与保护它的同步原语(Mutex)封装在同一个结构体中。

在共享内存的并发模型中,最大的噩梦是“锁与数据分离”。例如,你定义了一个全局变量 var Cache map[string]int,然后又定义了一个全局锁 var Mu sync.Mutex。随着代码量的增加,开发者很容易忘记在访问 Cache 时加锁,或者错误地使用了其他的锁。

论文建议采用一种“物理强绑定”的策略:

type SafeCounter struct {
    // 1. 将锁作为结构体的第一个字段
    mu sync.Mutex

    // 2. 受保护的数据应当是私有的(小写)
    // 强制外部必须通过方法来访问
    values map[string]int
}

// 3. 只有通过这个方法才能访问数据
func (c *SafeCounter) Inc(key string) {
    c.mu.Lock()
    // 4. 利用 defer 确保锁的释放与函数作用域绑定
    defer c.mu.Unlock()

    c.values[key]++
}

这种模式被称为 Monitor Pattern(监视器模式)。它通过封装强制实施了并发安全,将“会不会加锁”的问题变成了“能不能调用方法”的问题,后者由编译器保证,前者只能靠人品。

进阶——超越标准库的尝试

虽然标准库提供了 sync.WaitGroup 和 context,但要完美实现结构化并发,样板代码依然繁多。论文提到了社区中一些优秀的尝试,其中最值得关注的是 Sourcegraph 开源的 conc 库

conc 库试图解决标准库 WaitGroup 的两个痛点:

  1. Panic 逃逸:在标准 go func 中,如果子协程 panic,整个程序会直接崩溃(Crash),父协程无法 recover。这对于高可用服务是致命的。
  2. Error 传播:WaitGroup 不支持错误返回,需要开发者自己维护一个 err 变量或使用 errgroup。

conc 提供了增强版的 WaitGroup:

import "github.com/sourcegraph/conc"

func main() {
    var wg conc.WaitGroup

    wg.Go(func() {
        // 如果这里 panic 了
        panic("something went wrong")
    })

    // Wait() 会自动捕获子协程的 panic
    // 并将其重新抛出或作为错误返回(取决于具体 API)
    // 从而避免进程直接崩溃
    wg.Wait()
}

这种工具库的出现,标志着 Go 社区正在从“手动管理并发”向“自动化管理并发”演进,这正是结构化并发理念的工程化落地。

小结:从“能用”到“可控”

Go 语言通过 go 关键字将并发编程的门槛降到了历史最低,赢得了云计算时代的入场券。但在构建大规模、高可靠的系统时,我们不能止步于“能用”。

这篇学术论文为我们提供了一个冷静的视角:并发不是目的,只是手段。 失控的并发是灾难,只有受控的并发才是生产力。

结构化并发不是一种束缚,而是一种保护。它要求我们在写下每一个 go func 的时候,都要问自己三个问题:

  1. 它什么时候结束?
  2. 谁负责等待它结束?
  3. 如果它出错了,谁来处理?

只有当这三个问题都有明确答案时,我们才能说,我们真正掌握了 Go 的并发艺术。

参考资料


你更倾向于哪一派?

有人认为 Go 的自由是生产力之源,有人认为约束才是工程的救赎。在你的项目中,你是否也曾因为“射后不理”的 goroutine 踩过坑?你认为 Go 官方是否应该在语言层面引入类似 Java 或 Python 的结构化并发原生支持?

欢迎在评论区分享你的看法或“血泪史”!

想深入掌握 Go 并发调度的底层原理?点击查看我的微专栏《Go 并发调度艺术》。


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 从 0 开始构建 Agent Harness Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com
这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats