<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tony Bai &#187; 布道师</title>
	<atom:link href="http://tonybai.com/tag/%e5%b8%83%e9%81%93%e5%b8%88/feed/" rel="self" type="application/rss+xml" />
	<link>https://tonybai.com</link>
	<description>一个程序员的心路历程</description>
	<lastBuildDate>Fri, 17 Apr 2026 23:55:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Go早期的那些布道者</title>
		<link>https://tonybai.com/2024/05/17/the-early-evangelists-of-go/</link>
		<comments>https://tonybai.com/2024/05/17/the-early-evangelists-of-go/#comments</comments>
		<pubDate>Fri, 17 May 2024 13:43:39 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AndrewGerrand]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Ardan]]></category>
		<category><![CDATA[badger]]></category>
		<category><![CDATA[BillKennedy]]></category>
		<category><![CDATA[BradFitzpatrick]]></category>
		<category><![CDATA[BrianKetelsen]]></category>
		<category><![CDATA[cobra]]></category>
		<category><![CDATA[Context]]></category>
		<category><![CDATA[DaveCheney]]></category>
		<category><![CDATA[deps.dev]]></category>
		<category><![CDATA[Dgraph]]></category>
		<category><![CDATA[DmitryVyukov]]></category>
		<category><![CDATA[FrancescCampoy]]></category>
		<category><![CDATA[fuzzing]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go-fuzz]]></category>
		<category><![CDATA[go-nuts]]></category>
		<category><![CDATA[go.mod]]></category>
		<category><![CDATA[go1.18]]></category>
		<category><![CDATA[go1.23]]></category>
		<category><![CDATA[GoCourse]]></category>
		<category><![CDATA[GoExecutionTracer]]></category>
		<category><![CDATA[gohugo]]></category>
		<category><![CDATA[GoInAction]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[gomodule]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Gopher]]></category>
		<category><![CDATA[gopherchina]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[GoProgrammingBlueprints]]></category>
		<category><![CDATA[gops]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[GoTime]]></category>
		<category><![CDATA[govanityurls]]></category>
		<category><![CDATA[Go社区]]></category>
		<category><![CDATA[grafana]]></category>
		<category><![CDATA[hey]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[hugo]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[JaanaDogan]]></category>
		<category><![CDATA[JustForFunc]]></category>
		<category><![CDATA[KenThompson]]></category>
		<category><![CDATA[LiveJournal]]></category>
		<category><![CDATA[MatRyer]]></category>
		<category><![CDATA[Memcached]]></category>
		<category><![CDATA[NUMA]]></category>
		<category><![CDATA[pprof]]></category>
		<category><![CDATA[Rakyll]]></category>
		<category><![CDATA[RobertGriesemer]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[spf13]]></category>
		<category><![CDATA[statik]]></category>
		<category><![CDATA[SteveFrancia]]></category>
		<category><![CDATA[tailscale]]></category>
		<category><![CDATA[UltimateGo]]></category>
		<category><![CDATA[unique]]></category>
		<category><![CDATA[upspin]]></category>
		<category><![CDATA[vendor]]></category>
		<category><![CDATA[viper]]></category>
		<category><![CDATA[WireGurad]]></category>
		<category><![CDATA[workshop]]></category>
		<category><![CDATA[博客]]></category>
		<category><![CDATA[布道师]]></category>
		<category><![CDATA[接口]]></category>
		<category><![CDATA[播客]]></category>
		<category><![CDATA[标准库]]></category>
		<category><![CDATA[泛型]]></category>
		<category><![CDATA[调度器]]></category>
		<category><![CDATA[鼓吹者]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=4168</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2024/05/17/the-early-evangelists-of-go Go自2009年开源至今已经快15年了！这期间，有很多人对Go语言的发展做出了重要贡献，起到了至关重要的作用，他们被视为Go语言的早期布道者和鼓吹者。他们向Go社区传达着Go的价值观、Go的最新发展、Go的使用方法以及最佳实践。 这些人有来自Go团队的，有来自Google但非Go团队的，也有Go的早期采纳者和贡献者。如今这些人的状况不尽相同。有些人依然在活跃在Go团队中，为Go的演进持续做着贡献；有些人由于各种原因，已经退居二线，但仍心系Go的发展；还有一些人则逐渐淡出Go社区，或者说不再复当年的那种热忱。 不过，无论哪种，这些人为Go语言的推广和发展都做出了不可磨灭的贡献，值得Gopher们铭记。在这篇文章中，我就来说说这些Go早期的布道师。也可以让后进入Go阵营的Gopher们了解一下过去的事情。 注：这里是不完全统计，还有很多早期Go布道师做出了重要贡献，限于篇幅，这里就不一一列举细数了。 Rob Pike Rob Pike 是Go语言的共同创始人之一，他在2007年与Ken Thompson和Robert Griesemer一起开始了Go语言的开发。 作为一名经验丰富的计算机科学家，Rob Pike曾在贝尔实验室工作，参与了Plan 9和Inferno操作系统的开发，UTF-8也是他的杰作。此外，他还是C语言和UNIX操作系统的早期贡献者之一。 Rob Pike为Go语言的设计和实现做出了重大贡献。他的设计理念强调简洁、并发和高效，这些理念深深影响了Go语言的核心特性。在Go语言的早期发展阶段，Rob Pike几乎主导了Go语言规范的制定，并负责了许多关键语言特性的开发。在Ken Thompson退休后，他成为了Go语言第一代的领军人物。 除了技术贡献，Rob Pike还是最为积极的Go语言推广者。他在Google内外的各种会议和技术活动中发表演讲，介绍Go语言的优势、应用场景以及使用方法。他的演讲风格生动有趣，深受开发者的喜爱。此外，Rob Pike还撰写了大量关于Go语言的博客和技术文档，为社区提供了宝贵的学习资源。 截图来自golang.design 他的“3 Day Go Course”也是最早、最权威的Go教程，即便在今天看来略有些Outdated了:)。 注：关于Rob Pike的早期3-days Go Course ppt，可以在这里下载https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15440-f11/go/doc/ 现如今，Rob Pike已经从Google退休了，并长居澳大利亚，并继续为Go语言的发展做着贡献。尽管他不再像早期那样频繁地参与社区活动，但他的影响力依然深远，Go 1.18泛型发布前，Rob Pike就及时纠正了Go团队对泛型的支持策略。 Rob Pike的工作为Go语言奠定了坚实的基础，使其成为现代编程语言中的一颗璀璨明珠。 Robert Griesemer Robert Griesemer是Go语言的另一位共同创始人。他在加入Go团队之前，他曾参与Google V8 JavaScript引擎、Sawzall语言、Java HotSpot虚拟机和Strongtalk系统的工作，拥有丰富的编程语言设计和实现经验。 Griesemer在设计和实现Go语言方面发挥了关键作用，尤其是在语法和编译器的开发上。Griesemer的设计理念强调语言的简洁性和易用性，这使得Go语言在开发者中迅速获得了广泛的认可。他致力于优化编译器性能，使Go程序能够高效地运行在各种平台上。Griesemer还参与了Go语言标准库的设计和实现，为开发者提供了丰富的工具和资源。 在Go语言的推广方面，Griesemer同样不遗余力。他经常参与技术会议和社区活动，分享Go语言的设计理念和最佳实践，他也是唯一在GopherChina上现场进行分享的Go语言之父。 他的技术讲座深入浅出，帮助许多开发者快速上手Go语言。此外，Griesemer还与其他团队成员合作撰写了多篇技术论文和博客，进一步推动了Go语言的普及。 截图来自golang.design 目前，Griesemer依然在Google Go团队工作，奋战在Go语言的开发和优化的第一线。他和Ian Lance Taylor共同设计和实现了Go泛型机制，大幅提升了Go的表达能力。他的工作对Go语言的成功起到了至关重要的作用，使其成为许多大型项目和企业的首选开发语言。 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2024/05/17/the-early-evangelists-of-go">本文永久链接</a> &#8211; https://tonybai.com/2024/05/17/the-early-evangelists-of-go</p>
<p>Go自2009年开源至今<a href="https://tonybai.com/2023/11/11/go-opensource-14-years/">已经快15年了</a>！这期间，有很多人对Go语言的发展做出了重要贡献，起到了至关重要的作用，他们被视为<strong>Go语言的早期布道者和鼓吹者</strong>。他们向Go社区传达着Go的价值观、Go的最新发展、Go的使用方法以及最佳实践。</p>
<p>这些人有来自Go团队的，有来自Google但非Go团队的，也有Go的早期采纳者和贡献者。如今这些人的状况不尽相同。有些人依然在活跃在Go团队中，为Go的演进持续做着贡献；有些人由于各种原因，已经退居二线，但仍心系Go的发展；还有一些人则逐渐淡出Go社区，或者说不再复当年的那种热忱。</p>
<p>不过，无论哪种，这些人为Go语言的推广和发展都做出了不可磨灭的贡献，值得Gopher们铭记。在这篇文章中，我就来说说这些Go早期的布道师。也可以让后进入Go阵营的Gopher们了解一下过去的事情。</p>
<blockquote>
<p>注：这里是不完全统计，还有很多早期Go布道师做出了重要贡献，限于篇幅，这里就不一一列举细数了。</p>
</blockquote>
<h2><a href="https://en.wikipedia.org/wiki/Rob_Pike">Rob Pike</a></h2>
<p>Rob Pike 是Go语言的共同创始人之一，他在2007年与Ken Thompson和Robert Griesemer一起开始了Go语言的开发。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-2.jpeg" alt="" /></p>
<p>作为一名经验丰富的计算机科学家，Rob Pike曾在贝尔实验室工作，参与了Plan 9和Inferno操作系统的开发，UTF-8也是他的杰作。此外，他还是C语言和UNIX操作系统的早期贡献者之一。</p>
<p>Rob Pike为Go语言的设计和实现做出了重大贡献。他的设计理念<a href="https://time.geekbang.org/column/article/426740">强调简洁、并发和高效</a>，这些理念深深影响了Go语言的核心特性。在Go语言的早期发展阶段，Rob Pike几乎主导了Go语言规范的制定，并负责了许多关键语言特性的开发。在Ken Thompson退休后，他成为了Go语言第一代的领军人物。</p>
<p>除了技术贡献，Rob Pike还是<strong>最为积极的Go语言推广者</strong>。他在Google内外的各种会议和技术活动中发表演讲，介绍Go语言的优势、应用场景以及使用方法。他的演讲风格生动有趣，深受开发者的喜爱。此外，Rob Pike还撰写了大量关于Go语言的博客和技术文档，为社区提供了宝贵的学习资源。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-3.png" alt="" /><br />
<center>截图来自golang.design</center></p>
<p>他的<a href="https://tonybai.com/2012/08/23/the-go-programming-language-tutorial-part1/">“3 Day Go Course”</a>也是最早、最权威的Go教程，即便在今天看来略有些Outdated了:)。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-5.png" alt="" /></p>
<blockquote>
<p>注：关于Rob Pike的早期<a href="https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15440-f11/go/doc/">3-days Go Course ppt</a>，可以在这里下载https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15440-f11/go/doc/</p>
</blockquote>
<p>现如今，Rob Pike已经从Google退休了，并长居澳大利亚，并继续为Go语言的发展做着贡献。尽管他不再像早期那样频繁地<a href="https://tonybai.com/2024/01/07/what-we-got-right-what-we-got-wrong/">参与社区活动</a>，但他的影响力依然深远，<a href="https://tonybai.com/2022/04/20/some-changes-in-go-1-18">Go 1.18泛型</a>发布前，<a href="https://tonybai.com/2021/10/28/expectations-for-generics-in-go-1.18">Rob Pike就及时纠正了Go团队对泛型的支持策略</a>。</p>
<p>Rob Pike的工作为Go语言奠定了坚实的基础，使其成为现代编程语言中的一颗璀璨明珠。</p>
<h2><a href="https://en.wikipedia.org/wiki/Robert_Griesemer">Robert Griesemer</a></h2>
<p>Robert Griesemer是Go语言的另一位共同创始人。他在加入Go团队之前，他曾参与Google V8 JavaScript引擎、Sawzall语言、Java HotSpot虚拟机和Strongtalk系统的工作，拥有丰富的编程语言设计和实现经验。</p>
<p>Griesemer在设计和实现Go语言方面发挥了关键作用，尤其是在语法和编译器的开发上。Griesemer的设计理念强调语言的简洁性和易用性，这使得Go语言在开发者中迅速获得了广泛的认可。他致力于优化编译器性能，使Go程序能够高效地运行在各种平台上。Griesemer还参与了Go语言标准库的设计和实现，为开发者提供了丰富的工具和资源。</p>
<p>在Go语言的推广方面，Griesemer同样不遗余力。他经常参与技术会议和社区活动，分享Go语言的设计理念和最佳实践，他也是唯一在GopherChina上现场进行分享的Go语言之父。</p>
<p>他的技术讲座深入浅出，帮助许多开发者快速上手Go语言。此外，Griesemer还与其他团队成员合作撰写了多篇<a href="https://tonybai.com/2022/05/04/the-paper-of-go-programming-language-and-environment">技术论文和博客</a>，进一步推动了Go语言的普及。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-4.png" alt="" /><br />
<center>截图来自golang.design</center></p>
<p>目前，Griesemer依然在Google Go团队工作，奋战在Go语言的开发和优化的第一线。他和<a href="https://github.com/ianlancetaylor">Ian Lance Taylor</a>共同设计和实现了<a href="https://tonybai.com/2021/02/18/typing-generic-go-by-griesemer-at-gophercon-2020/">Go泛型机制</a>，大幅提升了Go的表达能力。他的工作对Go语言的成功起到了至关重要的作用，使其成为许多大型项目和企业的首选开发语言。</p>
<h2><a href="https://en.wikipedia.org/wiki/Brad_Fitzpatrick">Brad Fitzpatrick</a></h2>
<p>Brad Fitzpatrick是一位资深的美国程序员。在加入Go团队之前，Fitzpatrick就因创建LiveJournal和Memcached而闻名。后来加入Google，成为Go团队的重要成员，并在Go语言社区中拥有很高的声誉。</p>
<p>在Go语言的发展过程中，Fitzpatrick为许多关键组件做出了贡献，尤其是在网络库和并发编程模型方面。他创建了诸如HTTP包和<a href="https://github.com/golang/go/issues/14660">context包</a>等核心库，这些库广泛应用于Go语言的网络编程中。</p>
<p>Fitzpatrick不仅在技术上对Go做出了杰出贡献，他还是Go社区活动的积极参与者，是Go团队中参与社区活动的“典范”。他经常在技术会议和用户组活动中发表演讲，分享自己的经验和最佳实践。Fitzpatrick的工作帮助许多开发者更好地理解和使用Go语言，推动了社区的发展。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-6.png" alt="" /><br />
<center>截图来自golang.design</center></p>
<p>几年前，Fitzpatrick离开了Google并重新创业，他联创的<a href="https://github.com/tailscale">Tailscale</a>基于<a href="https://tonybai.com/2020/03/29/hello-wireguard/">WireGuard</a>和Go打造号称世界上最容易使用的安全private network产品。一些Go commiter和Ex-googler也被Fitzpatrick招入tailscale。Tailscale团队后续也成为了Go的重要贡献团队，比如<a href="https://github.com/go4org">go4org</a>下的很多实用包，像<a href="https://github.com/go4org/intern">intern</a>、<a href="https://tonybai.com/2023/04/16/understanding-unsafe-assume-no-moving-gc">unsafe-assume-no-moving-gc</a>、<a href="https://github.com/go4org/mem">mem</a>等。其中的intern还是<a href="https://github.com/golang/go/issues/62483">Go 1.23中加入的unique包</a>的灵感之源。</p>
<p>仍然活跃在Go开源社区的Fitzpatrick依旧继续为Go语言和其他开源项目做着贡献，他的热情和奉献精神使他成为Go社区中备受尊敬的领袖之一。</p>
<h2><a href="https://github.com/adg">Andrew Gerrand</a></h2>
<p>Andrew Gerrand是Go团队的早期成员之一，他为Go团队工作七年，早期也是Go项目的Top10贡献者。但他在Go团队的主要职责其实是围绕该语言构建社区并管理开源项目。Gerrand的工作帮助许多开发者快速上手Go语言。他编写的Go语言文章深入浅出，覆盖了从基础语法到高级特性的方方面面。此外，Gerrand还创建了Go Playground，一个在线编程环境，使开发者能够方便地编写和运行Go代码。</p>
<p>除了技术文档，Gerrand还积极参与社区活动。他组织和主持了多次Go语言会议（比如GopherCon）和用户组活动，推动了Go社区的建设和发展，是Rob Pike做Go社区推广的好搭档。。Gerrand还经常在Go语言的官方博客上发表文章，介绍Go的最新特性和最佳实践，官博早期的大部分文章都出自他手。由此看来，Gerrand在早期对Go语言的推广和社区建设做出过重要贡献。</p>
<p>从2016年开始，他跟随Rob Pike转战<a href="https://github.com/upspin/upspin">Upspin项目</a>，这个项目活跃了一年多，虽然现在依然在更新，但关注度目前已不是很高。Gerrand目前已经远离Go项目开发，并且很少撰文或参与Go社区活动。但他仍然在upspin、<a href="https://github.com/google/deps.dev">deps.dev</a>等google项目上使用Go进行着开发和维护工作。</p>
<p>如果要关注Gerrand的日常，可以<a href="https://twitter.com/enneff">在X上follow他的账号</a>。</p>
<h2><a href="https://swtch.com/~rsc/">Russ Cox</a></h2>
<p>Russ Cox是早期Go语言团队的重要成员之一，对Go语言的设计和实现做出了重大贡献。他拥有麻省理工学院的计算机科学博士学位，曾在贝尔实验室和Rob Pike一起在<a href="http://plan9.bell-labs.com/plan9">Plan9项目</a>上工作过。Cox在加入Google后，成为Go语言项目的核心开发者之一。</p>
<p>Russ Cox对Go的贡献是全方位的，无论在语言特性、工具链、社区推广等方面都有很大建树。这也使得他在Rob Pike退休后，迅速成为了Go语言的第二代领军人物。</p>
<p>近几年进入Go阵营的开发者对Russ Cox不可谓不熟悉，他主导了<a href="https://tonybai.com/2020/12/03/should-you-commit-the-vendor-folder-in-go">vendor</a>、type alias、<a href="https://go.dev/ref/mod">Go module</a>、<a href="https://tonybai.com/2022/03/25/intro-generics">泛型</a>等设计和实现，直接引领了Go的演进方向。</p>
<p>近几年，Russ Cox经常在GopherCon大会上代表Go团队发表主旨演讲，并在官博亲自撰文，向Go社区传达Go语言的演进思路与方向。经过多年历练，Russ Cox逐渐扛起了Go这杆大旗，接过了Rob Pike手中沉甸甸的Go接力棒。</p>
<h2><a href="https://github.com/dvyukov">Dmitry Vyukov</a></h2>
<p>Dmitry Vyukov是一位俄罗斯大神级程序员，英特尔并行编程黑带级程序员。加入Google后一直从事性能优化方面的工作，包括并发无锁算法、执行跟踪和竞争检测工具、fuzzing工具等。Vyukov虽然不是Go团队成员，但他对Go的贡献却是核心级的，主要包括：</p>
<ul>
<li><a href="https://tonybai.com/2017/06/23/an-intro-about-goroutine-scheduler/">Goroutine scheduler的设计和实现</a>，从G-M模型，到G-P-M模型，至今Goroutine scheduler还是在Vyukov实现的基础上修修补补的。他还提出了<a href="https://docs.google.com/document/d/1d3iI2QWURgDIsSR6G2275vMeQ_X7w-qxM2Vp7iGwwuM/pub">Go调度器的NUMA设计方案</a>，但目前尚未进入Go proposal流程</li>
<li><a href="https://tonybai.com/2021/06/28/understand-go-execution-tracer-by-example">Go execution tracer的设计和实现</a></li>
<li><a href="https://tonybai.com/2015/12/08/go-fuzz-intro/">设计和实现Go Fuzzing的早起雏形</a>，并<a href="https://tonybai.com/2021/12/01/first-class-fuzzing-in-go-1-18">推动Fuzzing进入Go项目</a>。</li>
</ul>
<p>除了技术贡献，Vyukov早期也会参与一些会议和社区活动，虽然不多，主要是推广Go execution tracer和<a href="https://tonybai.com/2015/12/08/go-fuzz-intro/">go-fuzz工具</a>。</p>
<p>目前，Vyukov依然在Google工作，也在继续为Go语言的发展做着力所能及的贡献。</p>
<h2><a href="https://spf13.com/about/">Steve Francia</a></h2>
<p>Steve Francia是早起Go语言社区的重要成员之一，对Go语言的推广和社区建设做出了重要贡献。Francia在加入Google之前，曾在MongoDB、Docker公司工作，拥有丰富的开发和管理经验。之后他加入Google，在Go语言项目中担任开发者关系经理，负责推动Go语言在企业中的应用。</p>
<p>Francia最为人称道的是他开发并开源的几个Go项目，包括<a href="https://tonybai.com/2015/09/23/intro-of-gohugo/">goHugo</a>、<a href="https://tonybai.com/2023/03/25/the-guide-of-developing-cli-program-in-go">Cobra</a>和<a href="https://tonybai.com/2022/09/20/use-viper-to-do-merge-of-yml-configuration-files/">viper</a>等。其中的hugo，一个基于Go语言的静态网站生成器，广受开发者的欢迎。</p>
<p>除了技术贡献，Francia还致力于社区建设。他组织和主持了多次Go语言会议和用户组活动，推动了Go社区的发展。Francia还在其<a href="https://spf13.com">个人博客</a>上撰写了大量关于Go语言的技术文档，为开发者提供了宝贵的学习资源。</p>
<p>目前，Francia已经离开了Google和Go团队，并在一家位于纽约的初创公司担任CTO。目前在Go社区，他已不再像以前那样活跃，但他的几个开源项目依然保持积极开发中，也有人协助他打理这些开源项目。</p>
<p>总之，Francia的工作对Go语言的普及和社区建设起到了重要的作用，帮助Go成为开发者们最喜爱的编程语言之一。</p>
<h2><a href="https://github.com/rakyll">Jaana Dogan</a></h2>
<p>Jaana Dogan是这个布道者列表中唯一的女性程序员。她曾是Go语言团队的一名工程师，对Go语言的性能优化、诊断和工具开发做出了重要贡献。但她在Go团队工作的时间并不长，很快就离开了Go团队，原因未知。目前她供职在github。</p>
<p>Dogan对社区的贡献主要体现在其<a href="https://rakyll.org/">关于Go的独特观点的博客文章</a>、<a href="https://go.dev/doc/diagnostics">诊断相关的技术文档</a>以及其开源的诸多项目，比如：<a href="https://github.com/rakyll/hey">hey</a>、<a href="https://github.com/google/gops">gops</a>、<a href="https://github.com/GoogleCloudPlatform/govanityurls">govanityurls</a>、<a href="https://github.com/rakyll/statik">statik</a>等。这些项目都不大，但却十分实用。</p>
<p>很多gopher中<a href="https://tonybai.com/2021/07/06/add-metrics-for-go-application-using-go-metrics">使用hey进行http压测</a>，gops则是高频使用的Go辅助诊断工具，govanityurls则是我的《<a href="https://tonybai.com/2021/09/03/the-approach-to-go-get-private-go-module-in-house">小厂内部私有Go module拉取方案</a>》的重要组件。statik也是<a href="https://tonybai.com/2021/02/25/some-changes-in-go-1-16">Go 1.16版本</a>引入<a href="https://tonybai.com/2020/12/12/a-forward-look-to-new-feature-of-go-1-16/">go:embed</a>之前在可执行文件中嵌入静态文件的一个可选工具。</p>
<p>Dogan在社区中以其深入的技术见解和乐于分享的态度，赢得了广泛的尊重和赞誉。不过，离开Google后，尤其是进入github后，Dogan在Go上面的投入似乎变少了很多，博客文章基本也不更新了，也没有新的开源项目产出，这对Go社区来说算是一个“损失”吧。</p>
<h2><a href="https://github.com/bketelsen">Brian Ketelsen</a>和<a href="https://github.com/erikstmartin">Erik St. Martin</a></h2>
<p>将Brian Ketelsen和Erik St. Martin放在一起说，是因为他们一起对Go语言以及Go社区的最大贡献就是共同创办了<a href="https://www.gophercon.com/">GopherCon</a>，这是全球最大也是最权威的Go语言开发者大会，每年都会吸引大量来自世界各地的Go开发者。GopherCon不仅是一个技术交流的平台，也是Go社区的重要聚会，促进了开发者之间的交流与合作。两人在组织和推动GopherCon的过程中，展示了他们对Go语言的热情和奉献精神。今年(2024年)也是GopherCon诞生的第10个年头，想必这又是一场Go语言和Go社区的盛会！</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-7.jpg" alt="" /></p>
<p>除了会议组织和社区活动，Ketelsen和St. Martin还与William Kennedy联合撰写了关于Go语言的技术书籍<a href="https://book.douban.com/subject/25858023/">《Go in Action》</a>。这本书深入浅出地介绍了Go语言的基础知识和实际应用，为开发者提供了系统的学习资源。此外，他们还参与了多个开源项目，为Go语言的生态系统做出了重要贡献。</p>
<p>目前，Ketelsen和St. Martin都供职于微软公有云团队，仍然活跃在Go社区。</p>
<h2><a href="https://www.campoy.cat/">Francesc Campoy</a></h2>
<p>Francesc Campoy是Go语言社区的知名讲师和布道者，对Go语言的推广和普及做出了重要贡献。Campoy在加入Google之前，曾在西班牙的一家软件公司工作，拥有丰富的开发经验。他在Go语言项目中担任开发者关系经理，负责向开发者推广Go语言。Campoy也曾作为GopherChina的嘉宾在多年前来到中国布道！</p>
<p>Campoy的工作帮助许多开发者快速上手Go语言。他制作了一系列高质量的Go语言视频教程“<a href="https://youtube.com/c/justforfunc">Just for func</a>”，涵盖了从基础语法到高级特性的方方面面。这些视频教程深入浅出，受到了广泛的欢迎。此外，Campoy还创建了Go语言的官方YouTube频道，定期发布技术讲座和演示，进一步推动了Go语言的普及。</p>
<p>2016年，Campoy从Google离职，加入<a href="https://dgraph.io/">Dgraph Labs</a>，负责原生GraphQL数据库<a href="https://github.com/dgraph-io/dgraph">dgraph</a>以及<a href="https://github.com/dgraph-io/badger">键值数据库badger</a>的开发。后来Dgraph labs内讧，Campoy转投到apple名下。</p>
<p>进入Apple后，Campoy就渐渐从Go社区淡出了。但他仍然会进行一些Go项目的开发，Github的activity中有他的一些活动记录，但更多地是对私有仓库的贡献。</p>
<h2><a href="https://dave.cheney.net/">Dave Cheney</a></h2>
<p>如果说Go团队之外，谁是大家最喜欢的Go布道师和意见领袖，<strong>矮胖子Dave Cheney</strong>肯定可以拿到数一数二的选票。</p>
<p>相信早期学过Go语言的Gopher们，没有没读过Dave Cheney的个人博客的。他的博客从2010开始写的内容就几乎都与Go相关，并且思维缜密，写作风格深入浅出，颇受Gopher欢迎。</p>
<p>很多人还参与过他在世界各地举办的Go用户活动。Dave Cheney也是来到中国GopherChina大会最多的Go布道师，为中国Gopher带来了精彩的演讲以及<a href="https://dave.cheney.net/practical-go/presentations/qcon-china.html">极具干货的大会前Workshop</a>。</p>
<p>除了技术资料外，Dave Cheney早期在Go项目的issue上、在<a href="https://groups.google.com/g/golang-nuts">go-nuts邮件列表</a>以及stackoverflow上也是非常活跃，非常乐于帮助那些想给Go项目做出贡献的gopher融入。同时他在github.com/pkg下开源的诸多项目也非常实用（比如https://github.com/pkg/errors），深受大家欢迎。</p>
<p>更多关于Dave Cheney对Go语言的贡献，可以阅读其<a href="https://dave.cheney.net/about">个人博客的about页面</a>。</p>
<p>不过不知何故，从2021年初开始，Dave Cheney的博客开始停更，他在社区的声音也逐渐消失。直到今年年初，Dave Cheney才又更新了一篇名为<a href="https://dave.cheney.net/2024/02/22/microblog-testmain-can-cause-one-to-question-reality">“Microblog: TestMain can cause one to question reality”</a>的文章。</p>
<p>不过从Dave Cheney的github Contribution activity来看，Dave仍然在大量的编写代码，只是这些代码是commit到private仓库的。</p>
<p>希望Dave Cheney能早日回归Go社区，并恢复当初的那份热忱。</p>
<h2><a href="https://twitter.com/goinggodotnet">Bill Kennedy</a></h2>
<p>Bill Kennedy是Go语言社区的知名讲师和布道者，对Go语言的推广和普及做出了重要贡献，并且这种贡献一直持续至今。</p>
<p>Kennedy是<a href="https://www.ardanlabs.com/">ardan labs</a>的CTO，也是该公司的主要讲师，他最拿手的Ultimate Go培训已经开办了十多年了，每年都会在全球进行很多场培训，此外，GopherCon大会前的Workshop总是少不了Bill Kennedy的training。</p>
<p>除了Training，Ardan Labs早期的博客文章也堪称精品，不少Gopher因这些文章而受益！Kennedy的工作主要是帮助许多开发者快速上手Go语言。他还撰写了多本关于Go语言的技术书籍，如《Go in Action》和《Ultimate Go》。这些书籍深入浅出，涵盖了从基础语法到高级特性的方方面面，为开发者提供了系统的学习资源。</p>
<p>除了技术培训，Kennedy还积极参与Go语言演进和Go社区活动之中，这其中一个最典型的事件就是2019年他代表广大Gopher用户发<a href="https://www.ardanlabs.com/blog/2019/07/an-open-letter-to-the-go-team-about-try.html">给Go团队的公开信</a>，极力组织不成熟的try关键字提案进入Go语言。</p>
<p>目前，Kennedy依然活跃在Go社区，继续推动Go语言的发展和普及。</p>
<h2><a href="https://github.com/matryer">Mat Ryer</a></h2>
<p>Mat Ryer是Go语言社区的一位资深开发者和布道者，他是一名英国程序员。他之前在Go社区非常活跃，积极参与技术会议和社区活动，分享Go语言在实际项目中的应用经验和最佳实践，其中最持久的莫过于主持<a href="https://changelog.com/gotime">Go Time播客</a>了！”Go Time”是一个专注于Go编程语言的播客节目。该播客由Changelog Media出品，主要内容涵盖了Go语言的新特性、最佳实践、社区新闻、工具和库的推荐，以及与Go生态系统相关的各种话题。节目通常会邀请Go社区的知名开发者、贡献者和专家作为嘉宾，分享他们的经验和见解。截至写本文时，该播客已经发布了315期，每期都有音频和<a href="https://github.com/thechangelog/transcripts/blob/master/gotime/">文字稿</a>。</p>
<p>除了上述活动，Mat Ryer还是<a href="https://book.douban.com/subject/26907929/">《Go Programming Blueprints》</a>一书的作者。</p>
<p>如今Mat Ryer依然活跃在Go社区，他供职于Grafana，依然从事着Go语言开源项目的开发，同时主持Go Time播客以及组织和参与各种Go用户会议。</p>
<h2>参考资料</h2>
<ul>
<li><a href="https://golang.design/history/">Go history</a> &#8211; https://golang.design/history/</li>
</ul>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">Gopher部落知识星球</a>在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时，我们也会加强代码质量和最佳实践的分享，包括如何编写简洁、可读、可测试的Go代码。此外，我们还会加强星友之间的交流和互动。欢迎大家踊跃提问，分享心得，讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落，享受coding的快乐! 欢迎大家踊跃加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2024, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2024/05/17/the-early-evangelists-of-go/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Golang Channel用法简编</title>
		<link>https://tonybai.com/2014/09/29/a-channel-compendium-for-golang/</link>
		<comments>https://tonybai.com/2014/09/29/a-channel-compendium-for-golang/#comments</comments>
		<pubDate>Mon, 29 Sep 2014 09:02:43 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[Actor]]></category>
		<category><![CDATA[BestPractice]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[Blogger]]></category>
		<category><![CDATA[Channel]]></category>
		<category><![CDATA[Concurrent]]></category>
		<category><![CDATA[container]]></category>
		<category><![CDATA[CSP]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[LXC]]></category>
		<category><![CDATA[Opensource]]></category>
		<category><![CDATA[Programmer]]></category>
		<category><![CDATA[TIOBE]]></category>
		<category><![CDATA[内存模型]]></category>
		<category><![CDATA[博客]]></category>
		<category><![CDATA[容器]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[布道师]]></category>
		<category><![CDATA[并发]]></category>
		<category><![CDATA[开源]]></category>
		<category><![CDATA[思考]]></category>
		<category><![CDATA[感悟]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://tonybai.com/?p=1551</guid>
		<description><![CDATA[在进入正式内容前，我这里先顺便转发一则消息，那就是Golang 1.3.2已经正式发布了。国内的golangtc已经镜像了golang.org的安装包下载页面，国内go程序员与爱好者们可以到&#34;Golang中 国&#34;，即golangtc.com去下载go 1.3.2版本。 Go这门语言也许你还不甚了解，甚至是完全不知道，这也有情可原，毕竟Go在TIOBE编程语言排行榜上位列30开外。但近期使用Golang 实现的一杀手级应用 Docker你却不该不知道。docker目前火得是一塌糊涂啊。你去国内外各大技术站点用眼轻瞥一下，如 果没有涉及到&#8220;docker&#8221;字样新闻的站点建 议你以后就不要再去访问了^_^。Docker是啥、怎么用以及基础实践可以参加国内一位仁兄的经验之作：《 Docker &#8211; 从入门到实践》。 据我了解，目前国内试水Go语言开发后台系统的大公司与初创公司日益增多，比如七牛、京东、小米，盛大，金山，东软，搜狗等，在这里我们可以看到一些公司的Go语言应用列表，并且目前这个列表似乎依旧在丰富中。国内Go语言的推广与布道也再稳步推进中，不过目前来看多以Go入 门与基础为主题，Go idioms、tips或Best Practice的Share并不多见，想必国内的先行者、布道师们还在韬光养晦，积攒经验，等到时机来临再厚积薄发。另外国内似乎还没有一个针对Go的 布道平台，比如Golang技术大会之类的的平台。 在国外，虽然Go也刚刚起步，但在Golang share的广度和深度方面显然更进一步。Go的国际会议目前还不多，除了Golang老东家Google在自己的各种大会上留给Golang展示自己的 机会外，由 Gopher Academy 发起的GopherCon 会议也于今年第一次举行，并放出诸多高质量资料，在这里可以下载。欧洲的Go语言大会.dotgo也即将开幕，估计后续这两个大会将撑起Golang技术分享 的旗帜。 言归正传，这里要写的东西并非原创，自己的Go仅仅算是入门级别，工程经验、Best Practice等还谈不上有多少，因此这里主要是针对GopherCon2014上的&#8220;舶来品&#8221;的学习心得。来自CloudFlare的工程师John Graham-Cumming谈了关于 Channel的实践经验，这里针对其分享的内容，记录一些学习体会和理解，并结合一些外延知识，也可以算是一种学习笔记吧，仅供参考。 一、Golang并发基础理论 Golang在并发设计方面参考了C.A.R Hoare的CSP，即Communicating Sequential Processes并发模型理论。但就像John Graham-Cumming所说的那样，多数Golang程序员或爱好者仅仅停留在&#8220;知道&#8221;这一层次，理解CSP理论的并不多，毕竟多数程序员是搞工程 的。不过要想系统学习CSP的人可以从这里下载到CSP论文的最新版本。 维基百科中概要罗列了CSP模型与另外一种并发模型Actor模型的区别： Actor模型广义上讲与CSP模型很相似。但两种模型就提供的原语而言，又有一些根本上的不同之处： &#160;&#160;&#160; &#8211; CSP模型处理过程是匿名的，而Actor模型中的Actor则具有身份标识。 &#160;&#160;&#160; &#8211; CSP模型的消息传递在收发消息进程间包含了一个交会点，即发送方只能在接收方准备好接收消息时才能发送消息。相反，actor模型中的消息传递是异步 的，即消息的发送和接收无需在同一时间进行，发送方可以在接收方准备好接收消息前将消息发送出去。这两种方案可以认为是彼此对偶的。在某种意义下，基于交 会点的系统可以通过构造带缓冲的通信的方式来模拟异步消息系统。而异步系统可以通过构造带消息/应答协议的方式来同步发送方和接收方来模拟交会点似的通信 方式。 &#160;&#160;&#160; &#8211; CSP使用显式的Channel用于消息传递，而Actor模型则将消息发送给命名的目的Actor。这两种方法可以被认为是对偶的。某种意义下，进程可 以从一个实际上拥有身份标识的channel接收消息，而通过将actors构造成类Channel的行为模式也可以打破actors之间的名字耦合。 二、Go Channel基本操作语法 Go Channel的基本操作语法如下： [...]]]></description>
			<content:encoded><![CDATA[<p>在进入正式内容前，我这里先顺便转发一则消息，那就是Golang 1.3.2已经正式发布了。国内的<a href="http://golangtc.com">golangtc</a>已经镜像了golang.org的安装包下载页面，国内go程序员与爱好者们可以到&quot;Golang中 国&quot;，即golangtc.com去下载go 1.3.2版本。</p>
<p><a href="http://golang.org">Go</a>这门语言也许你还不甚了解，甚至是完全不知道，这也有情可原，毕竟Go在<a href="http://www.tiobe.com">TIOBE</a>编程语言排行榜上位列30开外。但近期使用Golang 实现的一杀手级应用<a href="http://docker.com"> <b>Docker</b></a>你却不该不知道。docker目前火得是一塌糊涂啊。你去国内外各大技术站点用眼轻瞥一下，如 果没有涉及到&ldquo;docker&rdquo;字样新闻的站点建 议你以后就不要再去访问了^_^。Docker是啥、怎么用以及基础实践可以参加国内一位仁兄的经验之作：《 <a href="https://www.gitbook.io/book/yeasy/docker_practice">Docker &#8211; 从入门到实践</a>》。</p>
<p>据我了解，目前国内试水Go语言开发后台系统的大公司与初创公司日益增多，比如七牛、京东、小米，盛大，金山，东软，搜狗等，在<a href="https://github.com/qiniu/go/issues/15#issuecomment-55568731">这里</a>我们可以看到一些公司的Go语言应用列表，并且目前这个列表似乎依旧在丰富中。国内Go语言的推广与布道也再稳步推进中，不过目前来看多以Go入 门与基础为主题，Go idioms、tips或Best Practice的Share并不多见，想必国内的先行者、布道师们还在韬光养晦，积攒经验，等到时机来临再厚积薄发。另外国内似乎还没有一个针对Go的 布道平台，比如Golang技术大会之类的的平台。</p>
<p>在国外，虽然Go也刚刚起步，但在Golang share的广度和深度方面显然更进一步。Go的国际会议目前还不多，除了Golang老东家Google在自己的各种大会上留给Golang展示自己的 机会外，由 <span style="font-family: Ubuntu, Tahoma, sans-serif; font-size: 14px; line-height: 20px;"><a href="http://gopheracademy.com/">Gopher Academy</a> 发起的</span><a href="http://www.gophercon.com">GopherCon</a> 会议也于今年第一次举行，并放出诸多高质量资料，在<a href="https://github.com/gophercon/2014-talks">这里</a>可以下载。欧洲的Go语言大会<a href="http://www.dotgo.eu/">.dotgo</a>也即将开幕，估计后续这两个大会将撑起Golang技术分享 的旗帜。</p>
<p>言归正传，这里要写的东西并非原创，自己的Go仅仅算是入门级别，工程经验、Best Practice等还谈不上有多少，因此这里主要是针对GopherCon2014上的&ldquo;舶来品&rdquo;的学习心得。来自CloudFlare的工程师John Graham-Cumming谈了关于 Channel的实践经验，这里针对其分享的内容，记录一些学习体会和理解，并结合一些外延知识，也可以算是一种学习笔记吧，仅供参考。</p>
<p><b>一、Golang并发基础理论</b></p>
<p>Golang在并发设计方面参考了C.A.R Hoare的CSP，即Communicating Sequential Processes并发模型理论。但就像John Graham-Cumming所说的那样，多数Golang程序员或爱好者仅仅停留在&ldquo;知道&rdquo;这一层次，理解CSP理论的并不多，毕竟多数程序员是搞工程 的。不过要想系统学习CSP的人可以从<a href="http://www.usingcsp.com">这里</a>下载到CSP论文的最新版本。</p>
<p><a href="http://en.wikipedia.org/wiki/Communicating_sequential_processes">维基百科</a>中概要罗列了CSP模型与另外一种并发模型Actor模型的区别：</p>
<p>Actor模型广义上讲与CSP模型很相似。但两种模型就提供的原语而言，又有一些根本上的不同之处：<br />
	&nbsp;&nbsp;&nbsp; &#8211; CSP模型处理过程是匿名的，而Actor模型中的Actor则具有身份标识。<br />
	&nbsp;&nbsp;&nbsp; &#8211; CSP模型的消息传递在收发消息进程间包含了一个交会点，即发送方只能在接收方准备好接收消息时才能发送消息。相反，actor模型中的消息传递是异步 的，即消息的发送和接收无需在同一时间进行，发送方可以在接收方准备好接收消息前将消息发送出去。这两种方案可以认为是彼此对偶的。在某种意义下，基于交 会点的系统可以通过构造带缓冲的通信的方式来模拟异步消息系统。而异步系统可以通过构造带消息/应答协议的方式来同步发送方和接收方来模拟交会点似的通信 方式。<br />
	&nbsp;&nbsp;&nbsp; &#8211; CSP使用显式的Channel用于消息传递，而Actor模型则将消息发送给命名的目的Actor。这两种方法可以被认为是对偶的。某种意义下，进程可 以从一个实际上拥有身份标识的channel接收消息，而通过将actors构造成类Channel的行为模式也可以打破actors之间的名字耦合。</p>
<p><b>二、Go Channel基本操作语法</b></p>
<p>Go Channel的基本操作语法如下：</p>
<p><font face="Courier New">c := make(chan bool) //创建一个无缓冲的bool型Channel <br />
	c &lt;- x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //向一个Channel发送一个值<br />
	&lt;- c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //从一个Channel中接收一个值<br />
	x = &lt;- c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //从Channel c接收一个值并将其存储到x中<br />
	x, ok = &lt;- c&nbsp; //从Channel接收一个值，如果channel关闭了或没有数据，那么ok将被置为false</font></p>
<p><i>不带缓冲的Channel</i>兼具通信和同步两种特性，颇受青睐。</p>
<p><b>三、Channel用作信号(Signal)的场景</b></p>
<p>1、等待一个事件(Event)</p>
<p><font face="Courier New">等待一个事件，有时候通过close一个Channel就足够了。例如：</font></p>
<p><font face="Courier New">//testwaitevent1.go<br />
	package main</font></p>
<p><font face="Courier New">import &quot;fmt&quot;</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(&quot;Begin doing something!&quot;)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c := make(chan bool)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go func() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(&quot;Doing something&#8230;&quot;)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <i>close(c)</i><br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }()<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <i>&lt;-c</i><br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(&quot;Done!&quot;)<br />
	}</font></p>
<p>这里main goroutine通过&quot;<font face="Courier New">&lt;-c</font>&quot;来等待sub goroutine中的&ldquo;完成事件&rdquo;，sub goroutine通过close channel促发这一事件。当然也可以通过向Channel写入一个bool值的方式来作为事件通知。main goroutine在channel c上没有任何数据可读的情况下会阻塞等待。</p>
<p>关于输出结果：</p>
<p>根据《<a href="http://golang.org/ref/mem">Go memory model</a>》中关于close channel与recv from channel的order的定义：<span style="color: rgb(34, 34, 34); font-family: Helvetica, Arial, sans-serif; font-size: 16px; font-style: italic; line-height: normal;"><font face="Courier New">The closing of a channel happens before a receive that returns a zero value because the channel is closed.</font></span></p>
<p>我们可以很容易判断出上面程序的输出结果：</p>
<p><font face="Courier New">Begin doing something!<br />
	Doing something&#8230;<br />
	Done!</font></p>
<p>如果将<font face="Courier New">close(c)</font>换成<font face="Courier New">c&lt;-true</font>，则根据《Go memory model》中的定义：<font face="Courier New"><span style="color: rgb(34, 34, 34); font-size: 16px; font-style: italic; line-height: normal;">A receive from an unbuffered channel happens before the send on that channel completes.</span></font><br />
	&quot;<font face="Courier New">&lt;-c</font>&quot;要先于&quot;<font face="Courier New">c&lt;-true</font>&quot;完成，但也不影响日志的输出顺序，输出结果仍为上面三行。</p>
<p>2、协同多个Goroutines</p>
<p>同上，close channel还可以用于协同多个Goroutines，比如下面这个例子，我们创建了100个Worker Goroutine，这些Goroutine在被创建出来后都阻塞在&quot;<font face="Courier New">&lt;-start&quot;</font>上，直到我们在main goroutine中给出<u>开工</u>的信号：&quot;<font face="Courier New">close(start)&quot;</font>，这些goroutines才开始真正的并发运行起来。</p>
<p><font face="Courier New">//testwaitevent2.go<br />
	package main</font></p>
<p><font face="Courier New">import &quot;fmt&quot;</font></p>
<p><font face="Courier New">func worker(start chan bool, index int) {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;-start<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(&quot;This is Worker:&quot;, index)<br />
	}</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; start := make(chan bool)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i := 1; i &lt;= 100; i++ {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go worker(start, i)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(start)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select {} //deadlock we expected<br />
	}</font></p>
<p>3、Select</p>
<p>【select的基本操作】<br />
	select是Go语言特有的操作，使用select我们可以同时在多个channel上进行发送/接收操作。下面是select的基本操作。</p>
<p><font face="Courier New">select {<br />
	case x := &lt;- somechan:<br />
	&nbsp;&nbsp;&nbsp; // &#8230; 使用x进行一些操作</font></p>
<p><font face="Courier New">case y, ok := &lt;- someOtherchan:<br />
	&nbsp;&nbsp;&nbsp; // &#8230; 使用y进行一些操作，<br />
	&nbsp;&nbsp;&nbsp; // </font><font face="Courier New"><font face="Courier New">检查ok值判断someOtherchan是否已经关闭</font></font></p>
<p><font face="Courier New">case outputChan &lt;- z:<br />
	&nbsp;&nbsp;&nbsp; // &#8230; z值被成功发送到Channel上时</font></p>
<p><font face="Courier New">default:<br />
	&nbsp;&nbsp;&nbsp; // &#8230; 上面case均无法通信时，执行此分支<br />
	}</font></p>
<p>【惯用法：for/select】</p>
<p>我们在使用select时很少只是对其进行一次evaluation，我们常常将其与for {}结合在一起使用，并选择适当时机从for{}中退出。</p>
<p><font face="Courier New">for {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case x := &lt;- somechan:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // &#8230; 使用x进行一些操作</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case y, ok := &lt;- someOtherchan:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // &#8230; 使用y进行一些操作，<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 检查ok值判断someOtherchan是否已经关闭</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case outputChan &lt;- z:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // &#8230; z值被成功发送到Channel上时</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // &#8230; 上面case均无法通信时，执行此分支<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	} </font></p>
<p>【终结workers】</p>
<p>下面是一个常见的终结sub worker goroutines的方法，每个worker goroutine通过select监视一个die channel来及时获取main goroutine的退出通知。</p>
<p><font face="Courier New">//testterminateworker1.go</font><br />
	<font face="Courier New">package main</font></p>
<p><font face="Courier New">import (<br />
	&nbsp;&nbsp;&nbsp; &quot;fmt&quot;<br />
	&nbsp;&nbsp;&nbsp; &quot;time&quot;<br />
	)</font></p>
<p><font face="Courier New">func worker(die chan bool, index int) {<br />
	&nbsp;&nbsp;&nbsp; fmt.Println(&quot;Begin: This is Worker:&quot;, index)<br />
	&nbsp;&nbsp;&nbsp; for {<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; select {<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //case xx：<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //做事的分支<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case &lt;-die:<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fmt.Println(&quot;Done: This is Worker:&quot;, index)<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp; }<br />
	}</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp; die := make(chan bool)</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp; for i := 1; i &lt;= 100; i++ {<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; go worker(die, i)<br />
	&nbsp;&nbsp;&nbsp; }</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp; time.Sleep(time.Second * 5)<br />
	&nbsp;&nbsp;&nbsp; close(die)<br />
	&nbsp;&nbsp;&nbsp; select {} </font><font face="Courier New"><font face="Courier New">//deadlock we expected</font><br />
	}</font></p>
<p>【终结验证】</p>
<p>有时候终结一个worker后，main goroutine想确认worker routine是否真正退出了，可采用下面这种方法：</p>
<p><font face="Courier New">//testterminateworker2.go<br />
	package main</font></p>
<p><font face="Courier New">import (<br />
	&nbsp;&nbsp;&nbsp; &quot;fmt&quot;<br />
	&nbsp;&nbsp;&nbsp; //&quot;time&quot;<br />
	)</font></p>
<p><font face="Courier New">func worker(die chan bool) {<br />
	&nbsp;&nbsp;&nbsp; fmt.Println(&quot;Begin: This is Worker&quot;)<br />
	&nbsp;&nbsp;&nbsp; for {<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; select {<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //case xx：<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //做事的分支<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case &lt;-die:<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fmt.Println(&quot;Done: This is Worker&quot;)<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; die &lt;- true<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return<br />
	&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp; }<br />
	}</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp; die := make(chan bool)</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp; go worker(die)</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp; die &lt;- true<br />
	&nbsp;&nbsp;&nbsp; &lt;-die<br />
	&nbsp;&nbsp;&nbsp; fmt.Println(&quot;Worker goroutine has been terminated&quot;)<br />
	}</font></p>
<p>【关闭的Channel永远不会阻塞】</p>
<p>下面演示在一个已经关闭了的channel上读写的结果：</p>
<p><font face="Courier New">//testoperateonclosedchannel.go<br />
	package main</font></p>
<p><font face="Courier New">import &quot;fmt&quot;</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cb := make(chan bool)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(cb)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x := &lt;-cb<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;%#v\n&quot;, x)</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x, ok := &lt;-cb<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;%#v %#v\n&quot;, x, ok)</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ci := make(chan int)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(ci)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y := &lt;-ci<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;%#v\n&quot;, y)</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cb &lt;- true<br />
	}</font></p>
<p><font face="Courier New">$go run </font><font face="Courier New"><font face="Courier New">testoperateonclosedchannel.go</font><br />
	false<br />
	false false<br />
	0<br />
	panic: runtime error: send on closed channel</font></p>
<p>可以看到在一个已经close的unbuffered channel上执行读操作，回返回channel对应类型的零值，比如bool型channel返回false，int型channel返回0。但向close的channel写则会触发panic。不过无论读写都不会导致阻塞。</p>
<p>【关闭带缓存的channel】</p>
<p>将unbuffered channel换成buffered channel会怎样？我们看下面例子：</p>
<p><font face="Courier New">//testclosedbufferedchannel.go<br />
	package main</font></p>
<p><font face="Courier New">import &quot;fmt&quot;</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c := make(chan int, 3)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c &lt;- 15<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c &lt;- 34<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c &lt;- 65<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(c)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;%d\n&quot;, &lt;-c)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;%d\n&quot;, &lt;-c)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;%d\n&quot;, &lt;-c)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;%d\n&quot;, &lt;-c)</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c &lt;- 1<br />
	}</font></p>
<p><font face="Courier New">$go run testclosedbufferedchannel.go<br />
	15<br />
	34<br />
	65<br />
	0<br />
	panic: runtime error: send on closed channel</font></p>
<p>可以看出带缓冲的channel略有不同。尽管已经close了，但我们依旧可以从中读出关闭前写入的3个值。第四次读取时，则会返回该channel类型的零值。向这类channel写入操作也会触发panic。</p>
<p>【range】</p>
<p>Golang中的range常常和channel并肩作战，它被用来从channel中读取所有值。下面是一个简单的实例：</p>
<p><font face="Courier New">//testrange.go<br />
	package main</font></p>
<p><font face="Courier New">import &quot;fmt&quot;</font></p>
<p><font face="Courier New">func generator(strings chan string) {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strings &lt;- &quot;Five hour&#39;s New York jet lag&quot;<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strings &lt;- &quot;and Cayce Pollard wakes in Camden Town&quot;<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strings &lt;- &quot;to the dire and ever-decreasing circles&quot;<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strings &lt;- &quot;of disrupted circadian rhythm.&quot;<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(strings)<br />
	}</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strings := make(chan string)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go generator(strings)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for s := range strings {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;%s\n&quot;, s)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Printf(&quot;\n&quot;)<br />
	}</font></p>
<p><b>四、隐藏状态</b></p>
<p>下面通过一个例子来演示一下channel如何用来隐藏状态：</p>
<p>1、例子：唯一的ID服务</p>
<p><font face="Courier New">//testuniqueid.go<br />
	package main</font></p>
<p><font face="Courier New">import &quot;fmt&quot;</font></p>
<p><font face="Courier New">func newUniqueIDService() &lt;-chan string {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id := make(chan string)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go func() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var counter int64 = 0<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id &lt;- fmt.Sprintf(&quot;%x&quot;, counter)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; counter += 1<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }()<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return id<br />
	}<br />
	func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id := newUniqueIDService()<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i := 0; i &lt; 10; i++ {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(&lt;-id)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	}</font></p>
<p><font face="Courier New">$ go run testuniqueid.go<br />
	0<br />
	1<br />
	2<br />
	3<br />
	4<br />
	5<br />
	6<br />
	7<br />
	8<br />
	9</font></p>
<p>newUniqueIDService通过一个channel与main goroutine关联，main goroutine无需知道uniqueid实现的细节以及当前状态，只需通过channel获得最新id即可。</p>
<p><b>五、默认情况</b></p>
<p>我想这里John Graham-Cumming主要是想告诉我们select的default分支的实践用法。</p>
<p>1、select&nbsp; for non-blocking receive</p>
<p><font face="Courier New">idle:= make(chan []byte, 5) //用一个带缓冲的channel构造一个简单的队列</font></p>
<p><font face="Courier New">select {<br />
	case b = &lt;-idle:  //尝试从idle队列中读取<br />
	&nbsp;&nbsp;&nbsp; &#8230;<br />
	default:&nbsp; //队列空，分配一个新的buffer<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; makes += 1<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b = make([]byte, size)<br />
	}</font></p>
<p>2、select for non-blocking send</p>
<p><font face="Courier New">idle:= make(chan []byte, 5) </font><font face="Courier New"><font face="Courier New">//用一个带缓冲的channel构造一个简单的队列</font></font></p>
<p><font face="Courier New">select {<br />
	case idle &lt;- b: //尝试向队列中插入一个buffer<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&#8230;<br />
	default: //队列满？</font></p>
<p><font face="Courier New">}</font></p>
<p><b>六、Nil Channels</b></p>
<p>1、nil channels阻塞</p>
<p>对一个没有初始化的channel进行读写操作都将发生阻塞，例子如下：</p>
<p><font face="Courier New">package main</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var c chan int<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;-c<br />
	}</font></p>
<p><font face="Courier New">$go run testnilchannel.go<br />
	fatal error: all goroutines are asleep &#8211; deadlock!</font></p>
<p><font face="Courier New">package main</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var c chan int<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c &lt;- 1<br />
	}</font></p>
<p><font face="Courier New">$go run testnilchannel.go<br />
	fatal error: all goroutines are asleep &#8211; deadlock!</font></p>
<p>2、nil channel在select中很有用</p>
<p>看下面这个例子：</p>
<p><font face="Courier New">//testnilchannel_bad.go<br />
	package main</font></p>
<p><font face="Courier New">import &quot;fmt&quot;<br />
	import &quot;time&quot;</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var c1, c2 chan int = make(chan int), make(chan int)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go func() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; time.Sleep(time.Second * 5)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c1 &lt;- 5<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(c1)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }()</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go func() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; time.Sleep(time.Second * 7)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c2 &lt;- 7<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(c2)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }()</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case x := &lt;-c1:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(x)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case x := &lt;-c2:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(x)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(&quot;over&quot;)<br />
	}</font></p>
<p>我们原本期望程序交替输出5和7两个数字，但实际的输出结果却是：</p>
<p><font face="Courier New">5<br />
	0<br />
	0<br />
	0<br />
	&#8230; &#8230; 0死循环</font></p>
<p>再仔细分析代码，原来select每次按case顺序evaluate：<br />
	&nbsp;&nbsp;&nbsp; &#8211; 前5s，select一直阻塞；<br />
	&nbsp;&nbsp;&nbsp; &#8211; 第5s，c1返回一个5后被close了，&ldquo;case x := &lt;-c1&rdquo;这个分支返回，select输出5，并重新select<br />
	&nbsp;&nbsp;&nbsp; &#8211; 下一轮select又从&ldquo;case x := &lt;-c1&rdquo;这个分支开始evaluate，由于c1被close，按照前面的知识，close的channel不会阻塞，我们会读出这个 channel对应类型的零值，这里就是0；select再次输出0；这时即便c2有值返回，程序也不会走到c2这个分支<br />
	&nbsp;&nbsp;&nbsp; &#8211; 依次类推，程序无限循环的输出0</p>
<p>我们利用nil channel来改进这个程序，以实现我们的意图，代码如下：</p>
<p><font face="Courier New">//testnilchannel.go<br />
	package main</font></p>
<p><font face="Courier New">import &quot;fmt&quot;<br />
	import &quot;time&quot;</font></p>
<p><font face="Courier New">func main() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var c1, c2 chan int = make(chan int), make(chan int)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go func() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; time.Sleep(time.Second * 5)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c1 &lt;- 5<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(c1)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }()</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go func() {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; time.Sleep(time.Second * 7)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c2 &lt;- 7<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close(c2)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }()</font></p>
<p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case x, ok := &lt;-c1:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if !ok {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c1 = nil<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(x)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case x, ok := &lt;-c2:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if !ok {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c2 = nil<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(x)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if c1 == nil &amp;&amp; c2 == nil {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fmt.Println(&quot;over&quot;)<br />
	}</font></p>
<p><font face="Courier New">$go run testnilchannel.go<br />
	5<br />
	7<br />
	over</font></p>
<p>可以看出：通过将已经关闭的channel置为nil，下次select将会阻塞在该channel上，使得select继续下面的分支evaluation。</p>
<p><b>七、Timers</b></p>
<p>1、超时机制Timeout</p>
<p>带超时机制的select是常规的tip，下面是示例代码，实现30s的超时select：</p>
<p><font face="Courier New">func worker(start chan bool) {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeout := time.After(30 * time.Second)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // &#8230; do some stuff<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case &lt;- timeout:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	} </font></p>
<p>2、心跳HeartBeart</p>
<p>与timeout实现类似，下面是一个简单的心跳select实现：</p>
<p><font face="Courier New">func worker(start chan bool) {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; heartbeat := time.Tick(30 * time.Second)<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select {<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // &#8230; do some stuff<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case &lt;- heartbeat:<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&#8230; do heartbeat stuff<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
	} </font></p>
<p style='text-align:left'>&copy; 2014, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2014/09/29/a-channel-compendium-for-golang/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
