12 ms·
The free lunch is over: a fundamental turn toward concurrency in software (2005)
- rustybolt 5y agoPeople having been saying this for decades and while it's true, concurrency is still widely regarded as 'too hard'. I'm not sure if this is justified (e.g. concurrency is inherently too hard to be viable), or due to the lack of tooling/conventions/education.
- deleted 5y ago[deleted]
- nicoburns 5y ago> I'm not sure if this is justified (e.g. concurrency is inherently too hard to be viable), or due to the lack of tooling/conventions/education. I think it's the tooling. Rust's modelling of concurrency using it's type system (the Send and Sync traits) make concurrency pretty straightforward for most use cases. You still have to be super-careful when creating the core abstractions using unsafe code, but once you have them they can easily be shared as libraries and it's a compile error to violate the invariants. And this means that most projects will never have to write the hard parts themselves and get concurrency for close to free.
- pjmlp 5y agoI will go with lack of education as main issue.
- eternalban 5y agoMemory models are subtle. Temporal reasoning in context of h/w, e.g. multi-core coherence, and language runtime MM is non-trivial. So there is a baseline level of difficulty baked into the domain. Education certainly is necessary, but here can only inform of what needs to be considered, known pitfalls, patterns of concurrency, etc. As to OP, well it better be viable, because we certainly need to deal with it. So better tooling and conventions encapsulated in expert developed libraries. The education level required will naturally fall into the categories for those who will develop the tools/libraries, and those that will use them.
- rbanffy 5y ago> Temporal reasoning in context of h/w, e.g. multi-core coherence, and language runtime MM is non-trivial. Don’t OSs expose that in the sense you can pin a threads to closest cores according to the memory access you need?
- kwhitefoot 5y agoLack of real need I think. Most of the computers in the world are either dedicated embedded controllers or end user devices. Concurrency in embedded controllers is pretty much an ordinary thing and has been since the days of the 6502/Z80/8080. For end user devices the kind of concurrency that matters to the end user is also not extraordinary, plenty of things happen in the background when one is browsing, word processing, listening to music, etc. So that leaves concurrency inside applications and that just isn't something that affects most of the end users. There really isn't much for a word processor to actually do while the user is thinking about which key to press so it can do those few things that there was not time for during the keypress. Mostly what is needed is more efficient code. Niklaus Wirth was complaining that code was getting slower more quickly than hardware was getting faster forty years in 1995 and it seems that he is still right. See https://blog.frantovo.cz/s/1576/Niklaus%20Wirth%20-%20A%20Plea%20for%20Lean%20Software%20-%20OCR.pdf https://blog.frantovo.cz/s/1576/Niklaus%20Wirth%20-%20A%20Pl...
- dvfjsdhgfv 5y ago> So that leaves concurrency inside applications and that just isn't something that affects most of the end users. There really isn't much for a word processor to actually do while the user is thinking about which key to press so it can do those few things that there was not time for during the keypress. This obviously depends on the application. Whenever you need to wait for an app to finish an operation that is not related to I/O, there is some potential for improvement. If a CPU-bound operation makes you wait for more than, say, a minute, it's almost definitely a candidate for optimization. Whether multithreading is a good solution or not depends on each case - when you need to communicate/lock a lot, it might not make sense. A good part of the solution is figuring out if it makes sense, how to partition the work etc.; the other part of this hard work is implementing and debugging it.
- pjmlp 5y agoInteresting that you mention Wirth, since all his programming languages from Modula-2 onwards do expose concurrency and paralelism.
- spacechild1 5y ago> concurrency is still widely regarded as 'too hard'. The question is: by whom? High performance software, like game engines, DAWs or video editors, has been heavily multithreaded for a while now. Maybe it's consumer or business software that could profit from more multithreading? I don't know, because I don't work in those areas.
- criddell 5y agoThere's been a lot of work done in C++ concurrency. Some higher level libraries that leverage recent (primitive) additions are emerging and they look pretty cool. For example: https://github.com/David-Haim/concurrencpp https://github.com/David-Haim/concurrencpp
- bartread 5y ago> The question is: by whom? I do feel similarly, even though I wouldn't classify myself as a great engineer. I've been writing concurrent software in managed languages, such as Java and C#[0], from the very beginning of my career, up until today. The level of multithreading has varied, but it's always been there. For anything beyond basic CRUD it pretty much becomes a requirement, both on desktop and on the web[1]. That doesn't mean I've never had a tricky race condition to debug (and, yes, they're hard to debug) during development, but I've never shipped a concurrency related bug to production[2]. The canonical examples of concurrency gone wrong are things like giving somebody a deadly radiation dose from a medical device but, in terms of serious software bugs, I do wonder how common concurrency bugs are relative to other types of bug, and whether they're really more serious in aggregate than those other types of bug. [0] Admittedly these languages make it a lot easier to avoid shooting yourself in the foot than C and C++ do. [1] Also worth bearing in mind that an inherent property of most, if not all, distributed software is that it's also concurrent: the moment you have multiple processes running indepedently or interdependently you also usually have a concurrent system, with the potential for "distributed race conditions" to occur. I.e., if you have a SPA that also has a non-trivial back-end, you have a concurrent system - just spread across different processes, generally on different machines. [2] In the context of in-process concurrency. Distributed concurrency is a different matter.
- tuyiown 5y ago
- mkl95 5y agoThe rise of async programming in backend web dev is making some people even more confused about models. For instance, many senior engineers out there don't understand the difference between sync multithreaded and async single threaded.
- Xunjin 5y agoI kind doubt what I know, so looked for a nice SO link for those who don't know the difference :) https://stackoverflow.com/a/34681101 https://stackoverflow.com/a/34681101
- rramadass 5y agohttps://stackoverflow.com/questions/51007636/how-javascript-single-threaded-and-asynchronous https://stackoverflow.com/questions/51007636/how-javascript-...
- dmytroi 5y agoMy 5 cents would be wrong abstraction and wrong tooling, let me elaborate a bit of them: - Current abstractions are mostly based on POSIX threads and C++/Java memory models. I think they are poorly representing what is actually happening in hardware. For example Acquire barrier in C++ makes it really hard to understand that in hardware it equals to a flush of invalidation queue of the core, to sanity check your understanding try answering the question "do you need memory barriers if you have multithreaded application (2+ threads) running a lock-free algorithm on a single core?", correct answer is no, because same core always sees it's own writes as they would happen in program order, even if OOO pipeline would reorder them. Or threads, they seem to be an entity that can either run or stop, but in hardware there are no threads, CPU just jumps to a different point in memory (albeit through rings 3->0->3). Heck even whole memory allocation story, we have generations of developers thinking about memory allocation and it's safety, yet hardware doesn't have that concept at all, memory range mapping concept would be the closest to what MMU actually does. Hence the impedance mismatch between hardware and current low level abstractions created a lot of developers who "know" how all of this works but doesn't actually know, and a bit afraid to crush through layers. I want more engineers to not be afraid and be comfortable with all low level bits even if they would never touch them, because one day you will find a bug like broken compare-exchange implementation in LLVM or similar. - Tooling is way off, the main problem with multithreading is that it's all "in runtime" and dynamic, for example if I'm making a lockfree hashmap, the only way for me to get into the edgecases of my algorithm (like two threads trying to acquire same token or something) is to run a bruteforce test between multiple threads and wait until it actually happens. Bruteforce-test-development scales very poorly, and testing something like consensus algorithms for hundreds of threads is just a nightmare of complexity of test fixtures involved. Then you get into ok, so how much testing is enough? How do you measure coverage? Lines of code? Branches? Threads-per-line? When are you sure that your algorithm is correct? Don't get me wrong, I've seen it multiple times, simple 100 lines of code passing tons of reviews only for me to find a race condition (algorithmical one) half a year later, and now it's deployed everywhere and very costly to fix. Another way would be to skip all of that and start modeling your algorithms first, TLA+ is one of the better tools for that out there, prove that your model is correct, and then implement it. Using something like TLA+ can make your multithreading coding a breeze in any language. And probably absence of transactional memory also contributes greatly, passing 8 or 16 bytes around atomically is easy, but try 24 or 32? Now you need to build out an insanely complicated algorithm that involves a lot of mathematics just to prove that it's correct.
- samuell 5y agoI see a lot of potential in pipeline concurrency, as seen in dataflow (DF) and flow-based programming (FBP). That is, modeling computation as pipelines where one component sends data to the next component via message passing. As long as there is enough data it will be possible for multiple components in the chain to work concurrently. The benefits are that no other synchronization is needed than the data sent between processes, and race conditions are ruled out as long as only one process is allowed to process a data item at a time (this is the rule in FBP). The main blockers I think is that it requires quite a rethink of the architecture of software. I see this rethink happening in larger, especially distributed systems, which are modeled a lot around these principles already, using systems such as Kafka and message queues to communicate, which more or less forces people to model computations around the data flow. I think the same could happen inside monolithic applications too, with the right tooling. The concurrency primitives in Go are superbly suited to this in my experience, given that you work with the right paradigm, which I've been writing about before [1, 2], and started making a micro-unframework for [3] (though the latter one will be possible to make so much nicer after we get generics in Go). But then, I also think there are some lessons to be learned about the right granularity for processes and data in the pipeline. Due to the overhead of message passing, it will not make sense performance-wise to use dataflow for the very finest-grain data. Perhaps this in a sense parallels what we see with distributed computing, where there is a certain breaking point before which it isn't really worth it to go with distributed computing, because of all the overhead, both performance-wise and complexity-wise. [1] https://blog.gopheracademy.com/composable-pipelines-pattern/ https://blog.gopheracademy.com/composable-pipelines-pattern/ [2] https://blog.gopheracademy.com/advent-2015/composable-pipelines-improvements/ https://blog.gopheracademy.com/advent-2015/composable-pipeli... [3] https://flowbase.org https://flowbase.org
- jerf 5y ago"concurrency is still widely regarded as 'too hard'." Is it? There isn't going to be an official declaration from the Masters of Computer Science that "2019 was the year concurrency ceased being Too Hard." or anything. My perception is that it is steadily becoming less and less notable for a program to be "concurrent". Tooling is becoming better. Common practices are becoming better. (In fact, you could arguably take common practices back to the 1990s and even with the tools of the day, tame concurrency. While the tooling had its issues too, I would assert the problem was more the practices than the tooling.) Understanding of how to use it reasonably safely is steadily spreading, and runtimes that make it safer yet are starting to get attention. I'm not sure I've seen a case where there was a problem that ought to be using concurrency, but nobody involved could figure out any way to deal with it or was too afraid to open that door in a long time. There's still plenty of cases where it doesn't matter even now, of course, because one core is a lot of computing power on its own. But it seems to be that for everyone out there who would benefit from concurrency, they're mostly capable of using it nowadays. Not necessarily without issue, but that's an unfair bar; you can still get yourself in concurrency trouble in Haskell or Erlang, but it's a lot easier than it used to be to get it right.
- amelius 5y agoIf only GPUs were more common and easier to work with.
- Const-me 5y ago> If only GPUs were more common They are very common. In 2021 on Windows, is safe to assume the GPU does at least D3D 11.0. The last GPU which does not is Intel Sandy Bridge, discontinued in 2013. D3D 11.0 supports lots of features about GPGPU. The main issue with D3D11 is FP64 support being optional, the hardware may or may not support. > and easier to work with I don’t find neither DirectCompute 11, nor CUDA, exceptionally hard to work with. D3D12 and Vulkan are indeed hard, IMO.
- amelius 5y ago> I don’t find neither DirectCompute 11, nor CUDA, exceptionally hard to work with. It still sucks that, if you're not careful or unlucky, GPUs may interfere with normal video operation during setup. Also on one machine I'm getting "GPU lost" error messages every once in a while during a long computation, and I have no other option than to reboot my machine. Further, the form factor sucks. Every card comes with 4 or more DVI connectors which I don't need. If parallel is the future, then give me something that fits on the mainboard directly, and which is more or less a commodity. Not the proprietary crap that vendors are currently shoving at us.
- Const-me 5y ago> on one machine I'm getting "GPU lost" error messages every once in a while during a long computation, and I have no other option than to reboot my machine. If that’s your computer, just change the registry setting disabling the TDR. By default, Windows uses 2 seconds to limit max.pipeline latency. When exceeded, the OS resets the GPU, restarts the driver, and logs that “device lost” in the event log. If that’s your customer’s computer you have to be more creative and fix your compute shaders. When you have a lot of things to compute and/or you detect underpowered hardware, split your Dispatch() calls into a series of smaller ones. As a nice side effect, this minimizes effect of your application on 3D rendering things running on the same GPU by other programs. Don’t submit them all at once. Submit two initially then one at a time using ID3D11Query to track completion of these compute shaders. ID3D11Fence can do that better (can sleep on WaitForSingleObject saving electricity) but fences are less compatible unfortunately. That’s an optional feature introduced in Win10 post-release in some update, and e.g. VMWare SVGA 3D doesn’t support fences. > the form factor sucks. Every card comes with 4 or more DVI connectors which I don't need. Some datacenter GPUs, and newer mining GPUs come without connectors. The mainstream commodity cards to have connectors because the primary market for them is supposed to be gamers. > something that fits on the mainboard directly Unlikely to happen because thermals. Modern high-end GPUs consume more electricity than comparable CPUs, e.g. RTX 3090 needs 350W, similarly priced EPYC 7453 needs 225W.
- lincpa 5y agoIt's ultimate solution: The Grand Unified Programming Theory: The Pure Function Pipeline Data Flow with Principle-based Warehouse/Workshop Model Apple M1 chip is the best case. https://github.com/linpengcheng/PurefunctionPipelineDataflow https://github.com/linpengcheng/PurefunctionPipelineDataflow
- typon 5y agoI blame Python and Javascript. Two of the most popular languages without proper concurrency support.
- maattdd 5y agoYou mean parallelism ? JS has good concurrency support (event, async..)
- criddell 5y agoDid it in 2005 though? I think Python also has async / await support today.
- RegW 5y agoPerhaps in 2005 we were still able to call across browser frames and abusing the one thread per frame model. async / await isn't really concurrency. It's a mechanism for picking up the job after something else has been done (perhaps like a callback). In a way it's been an advantage of Javascript: one or two threads do all the work in a timely way without all that messy thread scheduling and context switches.
- spenczar5 5y agoThat’s concurrency without in-process parallelism.
- jerf 5y agoI find the distinction far less interesting than most people. I thing it's easier to think of parallelism simply as an interesting special case of concurrency, and to think of runtimes and systems that are "concurrent" but can't run literally simultaneously, like Javascript or Python, as simply accidents of history not worth specially writing into the definitions of our terms. Every year "concurrent" code that can't be scheduled to run on multiple CPUs simultaneously is less and less interesting. And I don't anticipate any new language coming out in the future that will try to be "concurrent but can only run on one CPU", so this meaning is just going to fade into history as a particular quirk of some legacy runtimes. No, I do not consider any runtime that can't run on multiple CPUs simultaneously to have "good" concurrency support. It would, at best, be bad concurrency support. Better than "no" support, sure, but not good in 2021. If a new language came out with that support, nobody would call it "good" support, they'd call it failing to even raise the table stakes a new language needs nowadays.
- rbanffy 5y agoOne thing I’d love to do is a Smalltalk implementation where every message is processed in a separate thread. Could be a nice educational tool, as well as a great excuse to push workstations with hundreds of cores.
- ardacinar 5y agoIsn't that just erlang? Snarkiness aside, that would be interesting. Not just as an educational tool, but it might be useful in the same way as erlang is (large, fault-tolerant, massively parallel systems). But with OOP instead of FP (Elixir attempts to be the "friendly"/more conventional version of erlang, but it is still very much a functional language).
- rbanffy 5y agoThe nice thing about doing a Smalltalk is that there is a colossal amount of software built on top of it. I'd love to know how much of that corpus could operate like this. I don't recall ever using locks, but I also never ran ST on a multicore machine either. It's just that the message-passing idea matches a many-core machine so well it's a shame not to play with it.
- scroot 5y agoInteresting idea. One could imagine a kind of Actor-Smalltalk where each object is actually its own "thread" (whatever that means at the VM level). The issue then becomes the asynchronous nature of the beast and how to "respond to" senders -- as you know, in current ST-80 like systems, returning from a method is the same as "responding," but this would no longer be the case. Another idea is this: in the ST-80 VM, the only "real" thing at the OS level is SmallInteger. Everything else is a true object reference. One could imagine expanding the base integer size to 128 bits and having all references also described at that size. The reason to do this would be that IPv6 uses 128-bit addresses, and therefore we could bind object references to IP addresses at a lower level. That aside, the fact that the Opensmalltalk VM is made inside of Smalltalk means that -- in theory -- a team could iterate to that point using the environment itself.
- limoce 5y agoThere seems to be no way to efficiently replay concurrent programs in a deterministic fashion on multiple cores. Nondeterminism makes parallelism and concurrency inherently hard and unfriendly to new comers. It becomes even more difficult in recent years due to architecture decisions: weak memory order makes things worse. Supposing you are going to write nontrivial concurrent programs like toy Raft, I believe that looking through RPC logs will be the most painful thing. In contrast, on a single core, gdb is good enough. And there are also advanced examples like VMware's fault-tolerant VM and FundationDB's deterministic simulation. If we can debug concurrent programs without dirty tricks, just like single-threaded ones, I guess utilizing concurrency will be as handy as calling a function.
- aseure 5y ago> There seems to be no way to efficiently replay concurrent programs in a deterministic fashion I wish there was something like Jepsen [1] broadly available to mainstream programming languages to do just that. [1] https://jepsen.io/consistency https://jepsen.io/consistency
- Const-me 5y ago> no way to efficiently replay concurrent programs in a deterministic fashion on multiple cores OpenMP with static scheduler and hardcoded count of threads? OpenMP ain’t a silver bullet, but for many practically useful scenarios it’s indeed as simple as calling a function.
- hderms 5y agowhat about if you throw in async IO into the mix? seems like you'd have to have some kind of vmware-like virtualization where you record all IO interrupts into a linearalizable log
- Const-me 5y agoWhen you throw async I/O in the mix it’s no longer just your application you’re debugging, it’s the whole OS with other processes, the OS kernel with these drivers and DMAs, and external hardware that’s not a code at all. Can be tricky to debug or implement, but when I need that I normally use async-await in C#. The debugger in the IDE is multi-threaded, and does support these tasks.
- rkangel 5y agoI find it interesting that the language that best deals with parallelism (IMO) was invented significantly before we moved in the multi-core direction. The programming language landscape evolved and developed in the face of multi-code - async being a classic example. But the language that's often held up as the best solution to any given parallelism problem is Erlang. Erlang was built as a good programming model for concurrency on a single core, and then when multi-core came along, SMP was 'just' a VM enhancement and no programs needed changing at all to get the full advantage of all the cores (barring some special cases).
- deleted 5y ago[deleted]
- ashleyn 5y agoThe writing was on the wall as early as the beginning of the Pentium 4 era. There was this assumption that clock speed would just continue to grow at the insane rates it did in the 80s and 90s, and then reality caught up when the Netburst architecture didn't scale well enough to avoid heat issues and crazy insane pipelines. When Intel rolled out the Core architecture, they went back to a P6-derived design, a microarchitecture that dated back to 1995 - effectively an admission that Netburst had failed.
- lostcolony 5y agoErlang was begun in 1986. It left the lab and was used for production products first in 1996. The Pentium 4 came out in 2000. So, an interesting aside, but not sure it's relevant to the parent comment.
- dleslie 5y agoAnd initial forays into many cores was decades earlier then that. Aside from big iron, going back to the early 60s, there was some business class devices like those made by Sequent: https://en.m.wikipedia.org/wiki/Sequent_Computer_Systems https://en.m.wikipedia.org/wiki/Sequent_Computer_Systems
- chrisseaton 5y ago
- flakiness 5y ago2005, when the most important platform was the desktop, when the virtualization was yet to be mature, and when the dominant system programming language is C++. Today CPU cores are sliced by cloud vendors to sell out in smaller portion, and the phones are hesitant to go many-core as it will eat your battery in light-speed. Dark silicon is spent for domain specific circuits like AI, media or networking instead of generic cores. Parallelism is still very hard problem in theory, but its practical need isn't as prevalent as we thought on a decade-plus ago, partly thanks for the cloud and mobile. For most of us, at least the parallelism is kind of solved-by-someone-else problem. It is left for the small number of experts. Concurrency is still there, but the situation is much better than before (async/await, immutable data types, actors...)
- dragontamer 5y agoThe free lunch isn't quite over, although significant advancements were made in parallel computing... it turns out that CPUs have been able to "auto-parallelize" your sequential code all along. Just not nearly as efficiently as explicitly parallel methodologies. In 2005, your typical CPU was a 2.2GHz Athlon 64 3700+. In 2021, your typical CPU is a Ryzen 5700x at 3.8 GHz. Single-threaded performance is far better than 72% faster however. The Ryzen 5700x has far more L3 cache, far more instructions-per-clock, far more execution resources than the ol' 2005 era Athlon. In fact, server-class EPYC systems are commonly in the 2GHz range, because low-frequency saves a lot on power and servers want lower power usage. Today's EPYCs are still far faster per-core than the Athlons of old. ------------- This is because your "single thread" is executed more-and-more in parallel today. Thanks to the magic of "dependency cutting" compilers, the compiler + CPU auto-parallelizes your code and runs them on the 8+ execution pipelines found on modern CPU "cores". Traditionally, the CPUs in the 90s had a singular pipeline. But the 90s and 00s brought forth out of order execution, as well as parallel execution pipelines (aka: superscalar execution). That means 2 or more pipelines execute your "sequential" code, yes, in parallel. Modern cores have more than 8 pipelines and are more than capable of 4+ or 6+ operations per clock tick. This is less efficient than explicit, programmer given parallelism. But it is far easier to accomplish. The Apple M1 continues this tradition of wider execution. I'm not sure if "sequential" is dead quite yet (even if there's a huge amount of machine working to auto-translate sequential into parallel technically... our code is largely written in a "sequential" fashion) ------------- But the big advancements after 2005 was the rise of GPGPU compute. It was always known that SIMD (aka: GPUs) were the most parallel systems, from the late 1980s and early 90s the SIMD supercomputers always had the most FLOPs. OpenCL and CUDA really took parallelism more / SIMD mainstream. And indeed: these SIMD systems (be it AMD MI100 or NVidia A100) are far more efficient and far higher compute capabilities than anything else. The only "competitor" on the supercomputer scale is the Fugaku supercomputer, with SVE (512-bit SIMD) ARM using HBM RAM (same as the high-end GPUs). SIMD seems like the obvious parallel compute methodology if you really need tons and tons of compute power.
- snickerer 5y agoI agree with this article a lot. The layers over layers of software bloat increased with the hardware speed. The general trade-off is: We make the software as slow as possible to have the shortest development time with the least educated programmers. "Hey web dev intern, click me a new UI in the next two hours! Hurry!" This intern-clicks-a-new-UI works because we have a dozen layers of incomprehension-supporting-technologies. You don't need to know how most parts of the machine are working, Several libraries, VMs, and frameworks will make you a bed of roses. My point is that we a overdoing it with the convenience for the developers. Today there is way too much complexity and bloat in our systems. And there are not enough programmers trained to handle memory management and similar low-level tasks. Or their bosses wouldn't allow it because the deadline, you know. I think the general trend is bad because there is no free lunch. No silver bullet. Everything is a trade-off. For example C is still important because C's trade-off between programming convenience and runtime efficiency is very good. You pay a lot and you get a lot. This is also true for parallel programming. To write highly efficient parallel code you need skill and education. No silver bullet tooling will make this less "hard". And here I see the irony. Faster CPUs were used to have lower educated devs delivering quicker. More parallel CPUs need higher skilled devs working slower to utilize the chip's full potential.
- vmchale 5y ago> More parallel CPUs need higher skilled devs working slower to utilize the chip's full potential. Parallelism isn't so bad, you can use a functional style a lot of the time! E.g. Futhark, the accelerate framework, APLs....
- dragontamer 5y agoBased on what I can tell... the programmers who made huge contributions to parallel compute are those programmers who grossly understood the hardware. It didn't matter if they were Java programmers (Azul), Lisp Programmers (1980s CM2: Steel / Hille), GPU programmers, or C programmers. If you understood the machine, you figured out a fast and concurrent solution.
- kaliszad 5y ago
- kvhdude 5y agoI recall transactional memory being pitched to take a bite out of lock overheads associated with multithreading. (as opposed to lockless algorithms). Has it become mainstream?
- kaliszad 5y agoIf you use Clojure than yes, software transactional memory is readily available. https://clojure.org/reference/refs https://clojure.org/reference/refs
- dang 5y agoPast related threads: The Free Lunch Is Over – A Fundamental Turn Toward Concurrency in Software - https://news.ycombinator.com/item?id=15415039 https://news.ycombinator.com/item?id=15415039 - Oct 2017 (1 comment) The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software (2005) - https://news.ycombinator.com/item?id=10096100 https://news.ycombinator.com/item?id=10096100 - Aug 2015 (2 comments) The Moore's Law free lunch is over. Now welcome to the hardware jungle. - https://news.ycombinator.com/item?id=3502223 https://news.ycombinator.com/item?id=3502223 - Jan 2012 (75 comments) The Free Lunch Is Over - https://news.ycombinator.com/item?id=1441820 https://news.ycombinator.com/item?id=1441820 - June 2010 (24 comments) Others?
- jmchuster 5y agoIt seems to me that where we really ended up was distributed systems. We solve problems by not just making our code concurrent to use more cores, but by also making it use more computers.
- r00fus 5y agoThere are security and latency issues that make distributed over multiple cores != multiple processors != multiple computers. Each step adds more complexity.