TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Go channels are bad

298 点作者 jtolds大约 9 年前

27 条评论

sagichmal大约 9 年前
This is a frustrating and overly-exasperated post which reaches conclusions that have always been part of the Go canon. APIs should be designed synchronously, and the callers should orchestrate concurrency if they choose -- yes! Channels are useful in some circumstances, but if you just want to synchronize access to shared memory (like the author&#x27;s example) then you should just use a mutex -- yes! These are well understood truths.<p>Novices to the language have a tendency to overuse channels. Here is Andrew Gerrand addressing precisely this point two years ago at GopherCon: <a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=u-kkf76TDHE&amp;t=815" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=u-kkf76TDHE&amp;t=815</a><p>Neither the referenced performance characteristics via Tyler Treat, nor the FUD surrounding channel-based program architecture, invalidate channels generally. One does have to think carefully about ownership hierarchies: only one goroutine gets to close the channel. And if it&#x27;s in a hot loop, a channel will always perform worse than a mutex: channels use mutexes internally. But plenty of problems are solved very elegantly with channel-based CSP-style message passing.<p>It&#x27;s unfortunate that articles like this are written and gain traction. The explicit instruction to [new] Go programmers is that they should <i>avoid</i> channels, even that they are badly implemented, and both of those things are false.
评论 #11211262 未加载
评论 #11211660 未加载
评论 #11211272 未加载
评论 #11211239 未加载
评论 #11211656 未加载
评论 #11214091 未加载
评论 #11228064 未加载
david-given大约 9 年前
I&#x27;ve always really, really liked Ada&#x27;s rendezvous-based concurrency.<p>There&#x27;s more to it than I can really describe here, but in effect it allows you to treat a thread as an object with methods; calling a method on the object sends a message to the thread. The thread&#x27;s main code can, at any point, block and wait for a message, or combination of messages.<p>The handling code looks like this:<p><pre><code> ...some code... accept DoSomething(value: in out integer) do ...some code here... end ...some more code... </code></pre> That causes the thread to block and wait for the message. When the message is sent, the caller blocks, the receiver runs the handler, then the caller resumes.<p>The beauty here is that inside the message handler, you know that the caller is blocked... which means it&#x27;s safe to pass parameters by pointer[<i>]. Everywhere the parameter&#x27;s in scope, the parameter is safe to use. The type system won&#x27;t let the thread store the pointer anywhere without copying the contents first, so you get zero-copy messaging </i>and* it&#x27;s failsafe.<p>You can also do really cool stuff with timeouts, guards, automatic thread termination, etc. Here&#x27;s a simple multithreaded queue (syntax and logic not guaranteed, it&#x27;s been a while):<p><pre><code> loop select when usage &lt; capacity =&gt; accept Push(value: in integer) do data[usage] := value; usage := usage + 1; end; or when usage &gt; 0 =&gt; accept Pop(value: out integer) do usage := usage - 1; value := data[usage]; end; or terminate; end select; end loop; </code></pre> Multithreaded! Blocks the client automatically if they pop while the queue&#x27;s empty or push while it&#x27;s full! Automatically terminates the thread when the last connection goes away and the thread leaves scope! Thread safe! Readable!<p>I&#x27;d love to be able to do this in a more mainstream language.<p>[*] This is a simplification. Ada&#x27;s pointers are not like other language&#x27;s pointers.
评论 #11211817 未加载
评论 #11211589 未加载
评论 #11211639 未加载
Animats大约 9 年前
Good points.<p>The author points out that channel teardown is hard. He&#x27;s right. Figuring out how to shut down your Go program cleanly can be difficult, especially since calling &quot;close&quot; on a closed channel causes a panic. You have to send an EOF on each channel so the receiver knows to stop. When you have a pair of channels going in opposite directions between two goroutines, and either end can potentially initiate shutdown, it gets messy.<p>At least in the original implementation, &quot;select&quot; for more than one option was really slow and complex. The single-input case was handled efficiently with generated code, but for N &gt; 1, a very general library mechanism with several heap allocations for each message was used. This means having both a wait for data and a timeout in a select puts you through the slow path. Not good. Someone did an analysis of existing programs and found that N=1 was most common, N=2 was reasonably common, and N&gt;2 was rare. N=2 needs special case support.<p>QNX interprocess messaging has a similar architecture. But they don&#x27;t have the panic on close problem, and timeout is handled efficiently. So you can generally shut things down by closing something. As each process is notified about the close, it closes any channels with which it is involved, even if some other process has already closed them. The closes thus cascade and everything shuts down cleanly. Processes that time out at a message receive check to see if the rest of the system is still running, and shut down if it&#x27;s not.<p>Go&#x27;s &quot;share by communicating&quot; would be more useful if Go had Rust&#x27;s borrow checker, so you could share data without races. Yes, Go has a run-time race detector, but that&#x27;s only useful if races are common enough that they occur during testing.
评论 #11211330 未加载
评论 #11211222 未加载
评论 #11211375 未加载
travjones大约 9 年前
This was a well-written and entertaining post. It represents the kind of self-reflection every programming community should encourage. Too often are devs zealously supportive of their language of choice without considering thoughtful critiques that could make their chosen language even better, and&#x2F;or present an alternate way of looking at things that makes one better at programming in general.
divan大约 9 年前
I didn&#x27;t get the point of example with Game and Player. The code behaves exactly how it&#x27;s told to. If you need some logic to handle conditions where all players have been disconnected - you should implement it, no matter how. Maybe you want to wait for some time for a new players and teardown only after this timeout. Or, maybe, you want to reuse this game object, moving to some kind of pool (like sync.Pool). Or, perhaps, you really want to wait forever for returning players. It&#x27;s not &#x27;mutex vs channels&#x27; example in any way.<p>It&#x27;s not &#x27;fix goroutine leak&#x27; it&#x27;s &quot;write the logic you want&quot;, it&#x27;s that simple.<p>Next, channels are slow, really? Send-receive operation on unbuffered channel typically takes around 300ns. Nanoseconds. 300 nanosecond in exchange of nice and safe way to express concurrent things - I wouldn&#x27;t even call it a tradeoff. It&#x27;s not slow at all in vast majority of cases. Of course, if you write that software that do care about nanoseconds and channels becomes your bottleneck - congratulations, you&#x27;re doing great, and you probably have to switch to C++, Rust or even Assembler.<p>But, please, don&#x27;t mislead people telling them, that channels are slow. They could be slow for your exact case, but it&#x27;s not the same.<p>I don&#x27;t really get the tone and arguments of the article. Some of the points are totally valid, but they easily falls into the &#x27;hey folks, be careful about this small thing you may misunderstand at the beginning&#x27; category. Pity.
评论 #11211933 未加载
评论 #11211666 未加载
评论 #11211665 未加载
Jabbles大约 9 年前
Effective Go has always said:<p><i>Do not communicate by sharing memory; instead, share memory by communicating.<p>This approach can be taken too far. Reference counts may be best done by putting a mutex around an integer variable, for instance.</i><p><a href="https:&#x2F;&#x2F;golang.org&#x2F;doc&#x2F;effective_go.html#sharing" rel="nofollow">https:&#x2F;&#x2F;golang.org&#x2F;doc&#x2F;effective_go.html#sharing</a>
评论 #11210990 未加载
评论 #11210862 未加载
评论 #11210978 未加载
advanderveer大约 9 年前
I see channels as an architectural option when it comes to structuring the communication between components of my software. Mutexes are another option that are more effective in situations where multiple threads may access the interface of a single structure. E.g I use channels to distribute os.Signals througout my software and a mutex for making a &quot;context&quot; structure thread safe. Right tool for the right job
评论 #11211049 未加载
dilap大约 9 年前
Funny timing for me -- last Friday I rewrote some code from channels to traditional sync primitives (to the code&#x27;s improvement), and I was musing in my head that while everyone always says &quot;don&#x27;t communicate by sharing, share by communicating, yada yada,&quot; it doesn&#x27;t seem to work out that way in practice.<p>I think the article is well-written, and clearly comes from a place of deep experience and understanding. Good stuff.
评论 #11211900 未加载
drdaeman大约 9 年前
Offtopic: that animated image is literally nauseating. Consider removing it, or making it animate just once and then halt. It was meant to be &quot;fun&quot; or whatever but, seriously, I wasn&#x27;t able to read the text when it looped over and over in the corner of the eye.
评论 #11211110 未加载
评论 #11211062 未加载
评论 #11211009 未加载
hacknat大约 9 年前
I think I&#x27;ve just come to accept that sychronization is the pain point in any language. It&#x27;s callbacks, promises, and the single event loop in nodejs. It&#x27;s channels in golang.<p>No one can come up with a single abstraction for synchronization without it failing in some regard. I code in go quite a bit and I just try to avoid synchronization like the plague. Are there gripes I have with the language? Sure, CS theory states that a thread safe hash table can perform just about as well as a none-thread safe, so why don&#x27;t we have one in go? However...<p>Coming up with a valid case where a language&#x27;s synchronization primitive fails and then flaming it as an anti-pattern (for the clicks and the attention, I presume) is trolling and stupid.
评论 #11211863 未加载
评论 #11211077 未加载
评论 #11211292 未加载
_0w8t大约 9 年前
The article presents very similar arguments to those that I read in a book from 1982 or so. It discussed channels in Ada and pointed out that without super smart compilers that would turn channels into mutex operations the code using channels would be slower and more complex due to the need to create an extra threads.<p>Base on that I can predict that in 2050 I will also read an article discussing channels in yet another language and advocating using mutexes instead...
_ph_大约 9 年前
I am not a Go veteran, but can see where this article is not helpful. Yes, channels are not a solve-everything. That is, why the Go library also contains mutexes etc. The game serving example could have been fixed by adding a channel to signalize that the game is finished. The game runner function should listen on the &quot;scores&quot; and the &quot;done&quot; channel with a select. Or, not use a channel at all. The channels are great, when you just want a completely safe method of communicating between goroutines, as long as the communication reasonably falls in the &quot;streaming&quot; behavior of the channel model.
woodcut大约 9 年前
I find it hard to read something when the language used is so patronising.
评论 #11210860 未加载
评论 #11210853 未加载
评论 #11210965 未加载
soroso大约 9 年前
From <a href="http:&#x2F;&#x2F;go-proverbs.github.io&#x2F;" rel="nofollow">http:&#x2F;&#x2F;go-proverbs.github.io&#x2F;</a>:<p>Channels orchestrate; mutexes serialize.
hacknat大约 9 年前
Should have been titled, &quot;Interesting Cases Where Go Channels Fail&quot;...
gravypod大约 9 年前
In non-critical things (not important to execution speed), is it still acceptable to use go channels? I&#x27;m always weary of using a mutex because then I have to spend a much larger amount of time checking to see if it will lock.
lazyjones大约 9 年前
Saving the highscore in a goroutine becomes more interesting if that action can block or simply take a while, both more realistic occurrences than such minimalistic examples.
hamburglar大约 9 年前
Non Go programmer here. Can someone explain the initial goroutine leak that is being addressed? I don&#x27;t see the issue.
评论 #11211630 未加载
评论 #11211510 未加载
评论 #11211441 未加载
评论 #11211514 未加载
tptacek大约 9 年前
You can express unbounded buffered channels in Go straightforwardly with the stacked channel idiom.
richard_todd大约 9 年前
I enjoyed the article and nodded along as I read it. But after, I felt like it was overstating its case a little. It puts up a toy implementation that kinda works, and then explains that to make it act correctly in the real world you have to add uglier code. I can&#x27;t really see blaming the language constructs for that... show me a language where that doesn&#x27;t happen!<p>I do appreciate that the article tries to deflate some of the hype about channels that you see when first investigating Go (I know I bought into it at first). After a little experience, I settled into a pattern of using channels for large-scale and orderly pipelines, and more typical mutexes and conditions for everything else. They have strengths and weaknesses, like all tools.
f2f大约 9 年前
the Clive[1] system uses a fork of the Go language which allows readers to close channels (I think it&#x27;s the most significant difference between the languages, if not the only one):<p><a href="http:&#x2F;&#x2F;syssoftware.blogspot.com&#x2F;2015&#x2F;06&#x2F;lsub-go-changes.html" rel="nofollow">http:&#x2F;&#x2F;syssoftware.blogspot.com&#x2F;2015&#x2F;06&#x2F;lsub-go-changes.html</a><p>--<p>1: <a href="http:&#x2F;&#x2F;lsub.org&#x2F;ls&#x2F;clive.html" rel="nofollow">http:&#x2F;&#x2F;lsub.org&#x2F;ls&#x2F;clive.html</a>
pklausler大约 9 年前
Channels are great, but I prefer lazy lists.
b169118大约 9 年前
How can I play the gifs again?
GhotiFish大约 9 年前
a nice feature of this post would be the ability to click on images to hide them.<p>Normally I have ublock to remove distracting elements.
elcct大约 9 年前
There is probably a large number of developers who think &quot;OMG my Go code doesn&#x27;t have any channels and goroutines. Am I doing this right?&quot; If you try to force a solution that isn&#x27;t quite right for the given problem, then well, have fun. Case presented by the author I would naturally program with Mutexes, as me thinks using channels &#x2F; goroutines is an overkill for this task.
PaulHoule大约 9 年前
Pixie dust that makes concurrency problems go away is an antipattern.
amelius大约 9 年前
This article should have been titled: &quot;Go channels considered harmful&quot; :)
评论 #11211038 未加载