From 189292a2ba360cb713802cb35f5fb50e82667d0c Mon Sep 17 00:00:00 2001 From: Xingyu Wang Date: Tue, 5 Jan 2021 10:12:37 +0800 Subject: [PATCH] PRF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @gxlct008 辛苦了! --- ...hannels are bad and you should feel bad.md | 66 ++++++++----------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/translated/tech/20160302 Go channels are bad and you should feel bad.md b/translated/tech/20160302 Go channels are bad and you should feel bad.md index 5d709ce33c..20523355d6 100644 --- a/translated/tech/20160302 Go channels are bad and you should feel bad.md +++ b/translated/tech/20160302 Go channels are bad and you should feel bad.md @@ -1,21 +1,21 @@ [#]: collector: (lujun9972) [#]: translator: (gxlct008) -[#]: reviewer: ( ) +[#]: reviewer: (wxy) [#]: publisher: ( ) [#]: url: ( ) [#]: subject: (Go channels are bad and you should feel bad) [#]: via: (https://www.jtolio.com/2016/03/go-channels-are-bad-and-you-should-feel-bad) [#]: author: (jtolio.com https://www.jtolio.com/) -Go 通道不好,你应该感觉很难过 +Go 通道是糟糕的,你应该也觉得很糟糕 ====== -> 更新:如果你是从一篇题为 《糟糕的 Go 语言》 的汇编文章看到这篇博文的话,那么我想表明的是,我很惭愧被列在这样的名单上。Go 绝对是我使用过的最不糟糕的的编程语言。在我写作本文时,我是想遏制我所看到的一种趋势,那就是过度使用 Go 的一些较复杂的部分。我仍然认为 -通道Channel可以更好,但是总体而言,Go 很棒。这就像你最喜欢的工具箱中有 [这个工具][1];它可以有用途(甚至还可能有更多的用途),它仍然可以成为你最喜欢的工具箱! -> -> 更新 2:如果我没有指出这项对真实问题的优秀调查,那我将是失职的:《[理解 Go 中的实际并发错误][2]》。这项调查的一个重要发现是...Go 通道会导致很多错误。 +更新:如果你是从一篇题为 《[糟糕的 Go 语言](https://github.com/ksimka/go-is-not-good)》 的汇编文章看到这篇博文的话,那么我想表明的是,我很惭愧被列在这样的名单上。Go 绝对是我使用过的最不糟糕的的编程语言。在我写作本文时,我是想遏制我所看到的一种趋势,那就是过度使用 Go 的一些较复杂的部分。我仍然认为 +通道Channel可以更好,但是总体而言,Go 很棒。这就像你最喜欢的工具箱中有 [这个工具][1];它可以有用途(甚至还可能有更多的用途),它仍然可以成为你最喜欢的工具箱! -从 2010 年中后期开始,我就断断续续地在使用 Google 的 [Go 编程语言][3],自 2012 年 1 月开始(在 Go 1.0 之前!),我就用 Go 为 [Space Monkey][4] 编写了合法的产品代码。我对 Go 的最初体验可以追溯到我在研究 Hoare 的 [通信顺序进程][5] 并发模型和 [Matt Might][7] 的 [UCombinator 研究组][8] 下的 [π-演算][6] 时,作为我([现在已重定向][9])博士工作的一部分,以更好地支持多核开发。Go 就是在那时发布的(多么巧合啊!),我当即就开始学习尝试了。 +更新 2:如果我没有指出这项对真实问题的优秀调查,那我将是失职的:《[理解 Go 中的实际并发错误][2]》。这项调查的一个重要发现是...Go 通道会导致很多错误。 + +从 2010 年中后期开始,我就断断续续地在使用 Google 的 [Go 编程语言][3],自 2012 年 1 月开始(在 Go 1.0 之前!),我就用 Go 为 [Space Monkey][4] 编写了合规的产品代码。我对 Go 的最初体验可以追溯到我在研究 Hoare 的 [通信顺序进程][5] 并发模型和 [Matt Might][7] 的 [UCombinator 研究组][8] 下的 [π-演算][6] 时,作为我([现在已重定向][9])博士工作的一部分,以更好地支持多核开发。Go 就是在那时发布的(多么巧合啊!),我当即就开始学习尝试了。 它很快就成为了 Space Monkey 开发的核心部分。目前,我们在 Space Monkey 的生产系统有超过 42.5 万行的纯 Go 代码(_不_ 包括我们所有的 vendored 库中的代码量,这将使它接近 150 万行),所以也并不是你见过的最多的 Go 代码,但是对于相对年轻的语言,我们是重度用户。我们之前 [写了我们的 Go 使用情况][10]。也开源了一些使用率很高的库;许多人似乎是我们的 [OpenSSL 绑定][11](比 [crypto/tls][12] 更快,但请保持 openssl 本身是最新的!)、我们的 [错误处理库][13]、[日志库][14] 和 [度量标准收集库/zipkin 客户端][15] 的粉丝。我们使用 Go、我们热爱 Go、我们认为它是目前为止我们使用过的最不糟糕的、符合我们需求的编程语言。 @@ -275,18 +275,15 @@ ctx.Done(func() { close(ch) }) ### 通道有什么好处? -当然,通道对于某些事情是有好处的(毕竟它们是一个通用容器),有些事情你只能用它们来做(比如 `select`)。 +当然,通道对于某些事情是有好处的(毕竟它们是一个通用容器),有些事情你只能用它们来做(比如 `select`)。 +#### 它们是另一种特殊情况下的通用数据结构 -#### 它们是另一个特殊大小写的通用数据结构 +Go 程序员已经习惯于对泛型的争论,以至于我一提起这个词就能感觉到 PTSD(创伤后应激障碍)的到来。我不是来谈论这件事的,所以擦擦额头上的汗,让我们继续前进吧。 -Go 程序员已经习惯于对泛型的争论,以至于我一提起这个词就能感觉到 PTSD (创伤后应激障碍)的到来。我不是来谈论这件事的,所以擦去额头上的汗水,让我们继续前进吧。 +无论你对泛型的看法是什么,Go 的映射、切片和通道都是支持泛型元素类型的数据结构,因为它们已经被特殊封装到语言中了。 -无论你对泛型的看法是什么,Go的映射、切片和通道都是支持泛型元素类型的数据结构,因为它们已经被特殊化为语言。 - -无论你对泛型的看法如何,Go 的映射、切片和通道都是支持泛型元素类型的数据结构,因为它们在语言中已经过特殊处理。 - -在一种不允许你编写自己的泛型容器的语言中,任何允许你更好地管理事物集合的东西都是有价值的。在这里,通道是支持任意值类型的线程安全数据结构。 +在一种不允许你编写自己的泛型容器的语言中,任何允许你更好地管理事物集合的东西都是有价值的。在这里,通道是一个支持任意值类型的线程安全数据结构。 所以这很有用!我想这可以省去一些陈词滥调。 @@ -296,8 +293,7 @@ Go 程序员已经习惯于对泛型的争论,以至于我一提起这个词 使用通道可以做的主要事情是 `select` 语句。在这里,你可以等待固定数量的事件输入。它有点像 epoll,但你必须预先知道要等待多少个套接字。 - -这是真正有用的语言功能。如果不是 `select`,通道将被彻底清洗。但是我的天呐,让我告诉你,有关你第一次决定可能需要在多个事物中选择,但是你不知道有多少项,因此必须使用 `reflect.Select`。 +这是真正有用的语言功能。如果不是 `select`,通道将被彻底清洗。但是我的天呐,让我告诉你,第一次决定可能需要在多个事物中选择,但是你不知道有多少项,因此必须使用 `reflect.Select`。 ### 通道如何才能更好? @@ -305,22 +301,19 @@ Go 程序员已经习惯于对泛型的争论,以至于我一提起这个词 #### 在条件变量上的 Select ! -We could just obviate the need for channels! This is where I propose we get rid of some sacred cows, but let me ask you this, how great would it be if you could select on any custom synchronization primitive? (A: So great.) If we had that, we wouldn’t need channels at all. - -我们可以不需要通道!这是我提议我们摆脱一些“圣牛”(神圣不可质疑的事物)的地方,但是让我问你,如果你可以选择任何自定义同步原语,那会有多棒? (答:太棒了。)如果有的话,我们根本就不需要通道了。 +我们可以不需要通道!这是我提议我们摆脱一些“圣牛sacred cows”(LCTT 译注:神圣不可质疑的事物)的地方,但是让我问你,如果你可以选择任何自定义同步原语,那会有多棒?(答:太棒了。)如果有的话,我们根本就不需要通道了。 #### GC 可以帮助我们吗? -在第一个示例中,如果我们能够使用定向类型的通道垃圾回收来帮助我们进行清理,我们就可以轻松地解决通道的高分服务器清理问题。 +在第一个示例中,如果我们能够使用定向类型的通道垃圾回收(GC)来帮助我们进行清理,我们就可以轻松地解决通道的高分服务器清理问题。 ![][31] +如你所知,Go 具有定向类型的通道。 你可以使用仅支持读取的通道类型(`<-chan`)和仅支持写入的通道类型(`chan<-`)。 这太棒了! -如您所知,Go 具有定向类型的通道。 您可以使用仅支持读取的通道类型(`<-chan`)和仅支持写入的通道类型(`chan <-`)。 这太棒了! +Go 也有垃圾回收功能。 很明显,某些类型的记账方式太繁琐了,我们不应该让程序员去处理它们。 我们清理未使用的内存! 垃圾回收非常有用且整洁。 -Go 也有垃圾收集功能。 很明显,某些类型的簿记方式太繁琐了,我们不应该让程序员去处理它们。 我们清理未使用的内存! 垃圾收集非常有用且整洁。 - -那么,为什么不帮助清理未使用或死锁的通道读取呢? 与其让 `make(chan Whatever)`返回一个双向通道,不如让它返回两个单向通道(`chanReader, chanWriter:= make(chan Type)`)。 +那么,为什么不帮助清理未使用或死锁的通道读取呢? 与其让 `make(chan Whatever)` 返回一个双向通道,不如让它返回两个单向通道(`chanReader, chanWriter:= make(chan Type)`)。 让我们重新考虑一下最初的示例: @@ -361,38 +354,35 @@ func (g *Game) HandlePlayer(p Player) error { } ``` -如果垃圾收集关闭了一个通道,而我们可以证明它永远不会有更多的值,那么这个解决方案是完全可行的。是的,是的,`run` 中的评论暗示着有一把相当大的枪瞄准了你的脚,但至少现在这个问题可以很容易地解决了,而以前确实不是这样。此外,一个聪明的编译器可能会做出适当的证明,以减少这种脚枪造成的损害。 +如果垃圾回收关闭了一个通道,而我们可以证明它永远不会有更多的值,那么这个解决方案是完全可行的。是的,是的,`run` 中的评论暗示着有一把相当大的枪瞄准了你的脚,但至少现在这个问题可以很容易地解决了,而以前确实不是这样。此外,一个聪明的编译器可能会做出适当的证明,以减少这种脚枪造成的损害。 -#### 其他较小的问题 +#### 其他小问题 * **Dup 通道吗?** —— 如果我们可以在通道上使用等效于 `dup` 的系统调用,那么我们也可以很容易地解决多生产者问题。 每个生产者可以关闭自己的 `dup` 版通道,而不会破坏其他生产者。 -* **修复通道API!** —— 关闭不是幂等的吗? 在已关闭的通道上发送信息引起的 panics 没有办法避免吗? 啊! +* **修复通道 API!** —— 关闭不是幂等的吗? 在已关闭的通道上发送信息引起的 panics 没有办法避免吗? 啊! * **任意缓冲的通道** —— 如果我们可以创建没有固定的缓冲区大小限制的缓冲通道,那么我们可以创建非阻塞的通道。 ### 那我们该怎么向大家介绍 Go 呢? -如果你还没有,请看看我目前最喜欢的编程文章:[你的功能是什么颜色][32]。虽然不是专门针对 Go,但这篇博文比我更有说服力地阐述了为什么 goroutines 是 Go 最好的特性(这也是 Go 在某些应用程序中优于 Rust 的方法之一)。 - +如果你还没有,请看看我目前最喜欢的编程文章:《[你的函数是什么颜色][32]》。虽然不是专门针对 Go,但这篇博文比我更有说服力地阐述了为什么 goroutines 是 Go 最好的特性(这也是 Go 在某些应用程序中优于 Rust 的方式之一)。 如果你还在使用这样的一种编程语言写代码,它强迫你使用类似 `yield` 关键字来获得高性能、并发性或事件驱动的模型,那么你就是活在过去,不管你或其他人是否知道这一点。到目前为止,Go 是我所见过的实现 M:N 线程模型(非 1:1 )的语言中最好的入门者之一,而且这种模型非常强大。 所以,跟大家说说 goroutines 吧。 -如果非要我选择 Go 的另一个主要特性,那就是接口。静态类型 [鸭子模型duck typing][33] 使得扩展,使用你自己或他人的项目变得如此有趣而令人惊奇,这也许值得我改天再写一组完全不同的文字。 - +如果非要我选择 Go 的另一个主要特性,那就是接口。静态类型的 [鸭子模型][33]duck typing 使得扩展、使用你自己或他人的项目变得如此有趣而令人惊奇,这也许值得我改天再写一组完全不同的文章来介绍它。 ### 所以… 我一直看到人们争先恐后冲进 Go,渴望充分利用通道来发挥其全部潜力。这是我对你的建议。 -**JUST STAHP IT** - -当你在编写 API 和接口时,尽管“绝不”的建议可能很糟糕,但我非常肯定,从来没有什么时候通道是更好的,我用过的每一个使用通道的 Go API,最后都不得不与之抗争。我从来没有想过“哦 太好了,这里是一个通道;”它总是被一些变体取代,_**这是什么新鲜的地狱?**_ +**够了!** +当你在编写 API 和接口时,尽管“绝不”的建议可能很糟糕,但我非常肯定,通道从来没有什么时候好过,我用过的每一个使用通道的 Go API,最后都不得不与之抗争。我从来没有想过“哦 太好了,这里是一个通道;”它总是被一些变体取代,_**这是什么新鲜的地狱?**_ 所以,_请在适当的地方,并且只在适当的地方使用通道。_ -在我使用的所有 Go 代码中,我可以用一只手数出有多少次通道真的是最好的选择。有时候是这样的。太好了!。那就用它们吧。否则就别说了。 +在我使用的所有 Go 代码中,我可以用一只手数出有多少次通道真的是最好的选择。有时候是这样的。那很好!那就用它们吧。但除此之外,就不要再使用了。 ![][34] @@ -404,10 +394,10 @@ _特别感谢我的校对读者 Jeff Wendling、[Andrew Harding][35]、[George S via: https://www.jtolio.com/2016/03/go-channels-are-bad-and-you-should-feel-bad -作者:[jtolio.com][a] +作者:[jtolds][a] 选题:[lujun9972][b] 译者:[gxlct008](https://github.com/gxlct008) -校对:[校对者ID](https://github.com/校对者ID) +校对:[wxy](https://github.com/wxy) 本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出