TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Must Be This Tall to Write Multi-Threaded Code

146 pointsby mnemonikalmost 10 years ago

29 comments

jandrewrogersalmost 10 years ago
The problems with traditional multi-threaded concurrency go beyond just complexity and safety. They also offer relatively poor performance on modern hardware due to the necessarily poor locality of shared structures and context switching, which causes unnecessary data motion down in the silicon. Whether or not &quot;message passing&quot; avoids this is dependent on the implementation.<p>Ironically, the fastest model today on typical multi-core silicon looks a lot like old school single-process, single-core event-driven models that you used to see when servers actually had a single core and no threads. One process per physical core, locked to the core, that has complete ownership of its resources. Other processes&#x2F;cores on the same machine are logically treated little different than if they were on another server. As a bonus, it is very easy to distribute software designed this way.<p>People used to design software this way back before multithreading took off, and in high-performance computing world they still do because it has higher throughput and better scalability than either lock-based concurrency or lock-free structures by a substantial margin. It has been interesting to see it make a comeback as a model for high concurrency server software, albeit with some distributed systems flavor that was not there in the first go around.
评论 #9905855 未加载
评论 #9906286 未加载
评论 #9908069 未加载
bsderalmost 10 years ago
Sigh. What&#x27;s wrong with using lock-free data structures?<p>Go study java.util.concurrent. It&#x27;s one of the absolute best libraries ever written by some of the smartest programmers I have ever seen.<p>The primary question is &quot;Do I really need to <i>wait</i> or do I just need to be <i>consistent</i>?&quot; 90% of the time the answer is that <i>consistent</i> is good enough.<p>Lock-free data structures are not a panacea. They don&#x27;t always do as well as locks in the face of contention. However, if you have that much contention, congratulations, you have an actual spot you really need to optimize.<p>By default, though, lock-free data structures protect you from so much fail it&#x27;s ridiculous. I don&#x27;t dread concurrent programming if I have a good lock-free data structure library.<p>That having been said, if you <i>really</i> have to wait (normally for hardware access), then you <i>MUST</i> do certain things. Your &quot;lock&quot; <i>MUST</i> be as small as possible--if it isn&#x27;t &quot;lock with timeout&quot;, &quot;single small action that always goes to completion even if error occurs&quot;, &quot;unlock&quot;--<i>YOU HAVE FAILED. START OVER</i>. Also, note the &quot;timeout&quot; portion of the lock. &quot;Timeout&quot; <i>MUST</i> be handled and <i>IS NOT NECESSARILY AN ERROR</i>.<p>Now, these don&#x27;t get all the situations. People who need &quot;transactions&quot; have hard problems. People who have high contention have hard problems.<p>However, I can count the number of times I genuinely needed to deal with contention or transactions on one hand and still have two fingers left over.<p>Whereas, I have lost count of the number of times that I cleared out all manner of bugs simply by switching to a lock-free data structure.
评论 #9907441 未加载
评论 #9906546 未加载
评论 #9906361 未加载
评论 #9907099 未加载
smegelalmost 10 years ago
I&#x27;ve written a lot of multi-threaded code, but I don&#x27;t think I&#x27;ve written ANY multi-threaded code that doesn&#x27;t involve queues passing objects (hopefully safely) between threads. As in, no locks, no semaphores, no accessing shared state between threads (OK apart from an global flag structure that just set various error conditions encountered and was only interacted with by atomic get&#x2F;set operations and where order of access was never important). Adding a lock to a program is like a huge red flag - stop everything and really think about what you are doing.
评论 #9907543 未加载
评论 #9907148 未加载
评论 #9906893 未加载
nickpsecurityalmost 10 years ago
Sounds like they&#x27;re just using the wrong tools. Eiffel&#x27;s SCOOP model[1] made things a lot easier back around &#x27;95. They&#x27;ve been improving on it since, with a lot of great work recently [2]. Various modifications proved absence of deadlocks, absence of livelocks, or guarantee of progress. I believe a version was ported to Java. A few modern variants have performance along lines of C++ w&#x2F; TBB and Go.<p>What are the odds that it could be ported to a restricted use of C++ language, I wonder?<p>Note: Ada&#x27;s concurrency strategy also prevented quite a few types of errors. They&#x27;re described in this article [3] on ParaSail, a language designed for easy concurrency that goes much further.<p>[1] <a href="http:&#x2F;&#x2F;cme.ethz.ch&#x2F;scoop&#x2F;" rel="nofollow">http:&#x2F;&#x2F;cme.ethz.ch&#x2F;scoop&#x2F;</a><p>[2] <a href="http:&#x2F;&#x2F;cme.ethz.ch&#x2F;publications&#x2F;" rel="nofollow">http:&#x2F;&#x2F;cme.ethz.ch&#x2F;publications&#x2F;</a><p>[3] <a href="http:&#x2F;&#x2F;www.embedded.com&#x2F;design&#x2F;programming-languages-and-tools&#x2F;4375616&#x2F;ParaSail--Less-is-more-with-multicore" rel="nofollow">http:&#x2F;&#x2F;www.embedded.com&#x2F;design&#x2F;programming-languages-and-too...</a>
tormehalmost 10 years ago
People: There are solutions to this shit. If you&#x27;re building a distributed system or need to deal with loss of data regardless, use actor systems (Erlang or Akka). If you need something that&#x27;s not quite as probabilistic and are willing to handle deadlocks use CSP (Go or Rust). If you need absolute determinism and you&#x27;re willing to pay for it in performance use SRP (Esterel or possibly maybe at your own risk Céu).<p>If you need shitstains in your underwear use locks and semaphores.
评论 #9907258 未加载
Animatsalmost 10 years ago
The main problem with multithreaded programming is that most languages are clueless about threads and locks. They were an afterthought in C, and were viewed as an operating system primitive, not a language primitive. The language has no clue what data is locked by which lock. There&#x27;s no syntax to even talk about that. Of course concurrency in C and C++ gets messed up.<p>Rust has a rational approach to shared data protection. Shared data is owned by a mutex, and you must borrow that mutex to access the data. You can have N read-only borrowers, or one read-write borrower. The borrow checker checks that at compile time. This gives us an enforceable way to think about who can access what.
评论 #9906507 未加载
SCHiMalmost 10 years ago
I got quite frustrated when I read this article. That&#x27;s because this article, and the many others like this, confuse the real issue.<p>This article, and those like it, all state that the problem with multi-threading and synchronization is inherent to the programing paradigm&#x2F;language&#x2F;architecture you&#x27;re using:<p>&gt; &quot;Buggy multi-threaded code creates race conditions, which are the most dangerous and time-consuming class of bugs in software&quot;<p>&gt; &quot;because the traditional synchronization primitives are inadequate for large-scale systems.&quot;<p>Ok. Fair enough, now tell us why that is so.<p>I get quite annoyed when the author then proceeds to turn it all around by saying this:<p>&gt; &quot;Locks don’t lend themselves to these sorts of elegant principles. The programmer needs to scope the lock just right so as to protect the data from races, while simultaneously avoiding (a) the deadlocks that arise from overlapping locks and (b) the erasure of parallelism that arise from megalocks. The resulting invariants end up being documented in comments:&quot;<p>&gt; &quot;And so on. When that code is undergoing frequent changes by multiple people, the chances of it being correct and the comments being up to date are slim.&quot;<p>Implying that the real problem with locks&#x2F;threading&#x2F;synchronization is actually communication, proper documentation discipline, programmer skill (soft and hard).<p>Of-course I&#x27;m not saying that the process of using primitive synchronization methods can&#x27;t be abstracted over to make it easier to write _proper_ multi threaded code. It&#x27;s just that this really feels like subjective politicking very much like the aversion to (proper use of) goto() in C&#x2F;C++ code.
评论 #9906095 未加载
SEMWalmost 10 years ago
&gt; In this approach, threads own their data, and communicate with message-passing. This is easier said than done, because the language constructs, primitives, and design patterns for building system software this way are still in their infancy<p>&quot;Still in their infancy&quot;? That&#x27;s basically a description of Erlang&#x27;s concurrency model, almost three decades old now.<p>Is there a concurrency equivalent of Spencer&#x27;s law -- something along the lines of &quot;<i>Those who do not understand Erlang are doomed to reinvent it</i>&quot;?
评论 #9905771 未加载
rayineralmost 10 years ago
It&#x27;s much easier to use threads than to use them properly. Arguably, the stricture&#x27;s of Rust&#x27;s type system makes it harder to use threads. But it makes it almost impossible to use threads improperly. Both are probably good things.<p>I have seen some real doosies writing multithreaded code. We had a relatively simple data analysis project that took in spectrum measurements from a piece of hardware, logged them, did some basic visualizations, and allowed for controlling the hardware. Each of these functions ran in one or more threads. Imagine my surprise when I saw lots of uses of CreateThread but nary a call to WaitForSingleObject or even EnterCriticalSection. I think there may have been a Boolean flag to &quot;coordinate&quot; a pair of producer&#x2F;consumer threads.
评论 #9905749 未加载
评论 #9905725 未加载
nbardyalmost 10 years ago
It seems like the key to writing current code is to abandon the idea of understanding how to construct a concurrent architecture and to figure out how to adopt a pattern concurrent which provides certain guarantees. Often it is something baked into the language, but frequently it is a library. This is one of the reasons I&#x27;m so thrilled with Clojure.<p>1) Because it has STM baked in and there is a core library for CSP.<p>2) Because it is a lisp so adding foreign syntax is as simple as a library and doesn&#x27;t need to be a language extension.
chipsyalmost 10 years ago
The article&#x27;s style got me into a ranting mood. I don&#x27;t want &quot;allusion links&quot; that surface vapid text like &quot;new superpowers&quot; or &quot;never ending stream of goodness&quot;. You are forcing me to click on them to know WTF you mean.
评论 #9907157 未加载
steven2012almost 10 years ago
I hate blog posts like this.<p>You get one guy, who is seemingly very smart, and he says basically &quot;Don&#x27;t do multithreading, it&#x27;s very hard. Only an elite few, such as me, can do this right, so most of you out there DON&#x27;T DO IT!&quot;<p>It&#x27;s bullshit. Mainly because it&#x27;s no harder than anything else, and has just as much pitfalls as every other type of programming. Yes, to a certain degree multithreading is hard, but it&#x27;s not rocket science. But PROGRAMMING is hard. Not just multithreaded programming. There&#x27;s nothing very special about multithreaded programming that should scare off people from trying it. Sure, you might fuck up, but that&#x27;s<p>For example, our entire company was almost completely brought down a few months ago by our &quot;architect&quot; implementing a feature so poorly that it caused massive system instability. What was this feature? It essentially boiled down to a 1 or a 2. Customer accounts were tagged with either a 1 or a 2, an it&#x27;s supposed to take a different code path for each, but he made it so fucking complicated and he didn&#x27;t do his due diligence, the entire weight of his code cause significant downtime, and a customer that accounts for 60% of our revenues almost walked. And none of this is rocket science.<p>Of course, I worked at another company where one engineer thought &quot;oh, asynchronous APIs are faster than synchronous APIs&quot; so they implemented the entire API asynchronously. Of course, that required mutexes on the server side. And then more mutexes. And it got to the point where the performance was hell because of the unintended consequences of trying to make things faster. You would write a new API and the server would barf saying &quot;You took the locks in the wrong order&quot; but there was no indication of you ever doing anything wrong. It was a mess. So I get what the OP is saying, but it&#x27;s not specific to just multithreadedness. I bet the same programmer would have made a mess of a single-threaded app as well. They are just shitty or careless programmers.<p>If you&#x27;re careful, multithreaded programming is helpful and you can see some significant performance boosts from it. But like <i>every other paradigm in programming</i>, don&#x27;t overuse it. A judicious use of simple multithreaded programming might help a lot, but there are few apps that benefit from an extremely complex system with hundreds of threads, massive amounts of mutexes, etc.
评论 #9906745 未加载
评论 #9907034 未加载
mannykannotalmost 10 years ago
&quot;The resulting invariants end up being documented in comments.&quot;<p>There&#x27;s your problem. If you are going to use locks, you need a wider view of the system than you get at the source-code level. It is doable, but there is a big impedance mismatch between this approach to software development and agile methods.
tsothaalmost 10 years ago
It&#x27;s really not that hard to write multi-threaded code. I just laugh when I read articles like this - I&#x27;ve been doing it for more than fifteen years now. By taking a tool like that away from your team you&#x27;re stunting their growth and your product.
评论 #9907513 未加载
jonduboisalmost 10 years ago
Thread-based concurrency has no future. It&#x27;s complex and it doesn&#x27;t scale beyond a certain point. Process-based concurrency is relatively simple (especially if your programming language has good async support) and it can scale indefinitely.<p>The one advantage of threads is that the overhead is lower when operating at low concurrency. But it&#x27;s like algorithmic complexity, people only care about growth in complexity not about the initial offset.
评论 #9906709 未加载
评论 #9905888 未加载
MCRedalmost 10 years ago
Erlang and Elixir solved this problem. I only write multi-threaded code in very limited cases when it makes sense to split processing out of UI on mobile devices.<p>Everywhere else I use Elixir, and I write multi-process code and I don&#x27;t think twice about it.<p>And I never run into problems.<p>I&#x27;m really feeling like people keep choosing tools that haven&#x27;t solved the problem, or even tried to, and then thinking that the problem is perennial.<p>It was solved a long time ago by erlang.
评论 #9906992 未加载
zzzcpanalmost 10 years ago
&gt; However, these programmers aren’t fleeing concurrency itself - they’re fleeing concurrent access to the same data.<p>He&#x27;s not wrong.<p>Modern real world example: Golang authors designed net library in a such way, that everyone who uses it has to think about concurrent access to shared mutable states. Which is hard and unnecessary. Event loops never had this problem, but for some reason got labeled &quot;non idiomatic&quot; by Golang folks. So I had to implement event loop myself.
atsalolialmost 10 years ago
Sigh. No mention of logic verification that there are no race conditions. Problem has been solved by Dr Holzmann at JPL <a href="http:&#x2F;&#x2F;www.verticalsysadmin.com&#x2F;making_robust_software&#x2F;" rel="nofollow">http:&#x2F;&#x2F;www.verticalsysadmin.com&#x2F;making_robust_software&#x2F;</a>
zubirusalmost 10 years ago
&gt;&gt; In this approach, threads own their data, and communicate with message-passing.<p>This is the same paradigm as MPI, the message parsing interface. Using it, you also get for free the ability to deploy your &quot;threaded&quot; code in distributed memory architectures. But any person who had just a bit of experience with this standard can tell you how tedious is to develop a parallel code with it. Maybe this is product of the paradigm or just the verbosity of the API (see for example: <a href="http:&#x2F;&#x2F;www.mpich.org&#x2F;static&#x2F;docs&#x2F;v3.1&#x2F;www3&#x2F;MPI_Alltoallv.html" rel="nofollow">http:&#x2F;&#x2F;www.mpich.org&#x2F;static&#x2F;docs&#x2F;v3.1&#x2F;www3&#x2F;MPI_Alltoallv.htm...</a>).I wish there was some sort of OpenMP or Intel TBB equivalent for MPI to ease out the pain.
aidenn0almost 10 years ago
My dad said he had to read Hoare when he got his M.S. in the eary &#x27;80s, and that half the people who read it didn&#x27;t understand it, and half the people who understood it ignored it. It&#x27;s 30 years later and people are still using crappy synchronization primitives.
ddmillsalmost 10 years ago
There is a relatively new actor-like language called paninij[1] which uses the idea of &#x27;capsules&#x27;. I have been developing a java annotation based version of it called `@PaniniJ`. Capsule oriented programming enforces modular reasoning, which in turn allows the code to be transformed automatically into multithreaded goodness.<p>[1] <a href="http:&#x2F;&#x2F;paninij.org&#x2F;" rel="nofollow">http:&#x2F;&#x2F;paninij.org&#x2F;</a> [2] <a href="https:&#x2F;&#x2F;github.com&#x2F;hridesh&#x2F;panini" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;hridesh&#x2F;panini</a>
评论 #9905786 未加载
rpcope1almost 10 years ago
I think you really ought to have to read Little Book of Semaphores before you&#x27;re allowed to touch multi-threaded code. [1]<p>[1] - <a href="http:&#x2F;&#x2F;www.greenteapress.com&#x2F;semaphores&#x2F;downey05semaphores.pdf" rel="nofollow">http:&#x2F;&#x2F;www.greenteapress.com&#x2F;semaphores&#x2F;downey05semaphores.p...</a>
ArkyBeaglealmost 10 years ago
I am utterly ignorant of what Gecko looks like, but in largerish realtime embedded work, things always seem to end up in more formal design methodologies utilizing transactional models such as message sequences ( frequently expressed in charts. )
kabdibalmost 10 years ago
Coroutines are great stuff. Being able to yield for an async result and then wake up later, without having to do expensive and buggy lock rendezvous nonsense, is manageable and scalable.
hyperpalliumalmost 10 years ago
Shared-nothing message passing is an answer, as used in Erlang, but I seem to recall reading that race and deadlock can still occur, just at a higher level.
opnitroalmost 10 years ago
Just so you know, this is broken on ios-safari. I love the title though.
zobzualmost 10 years ago
Love this sign, too bad I heard its gone
bronzalmost 10 years ago
What is racing?
评论 #9905692 未加载
评论 #9905722 未加载
batoualmost 10 years ago
Run this in your browser&#x27;s console window to make it actually scrollable without playing find the sodding scrollbar:<p><pre><code> document.getElementById(&quot;contentpane&quot;).style.width = &quot;100%&quot;</code></pre>
评论 #9905617 未加载