6 ms·
His solutions is threads? Really? Has he read no history? There are problems with threads. That's why async I/O is hot right now. Threads is a limited resource.
by Nilzor 12y ago
His solutions is threads? Really? Has he read no history? There are problems with threads. That's why async I/O is hot right now. Threads is a limited resource. Threads are expensive to create and dispose. Context switches are espensive. Threads must be synchronized. Threads can have race conditions.
Good rant, but I didn't expect him to serve such a shallow conclusion after a solid and insightful introduction.
- nkohari 12y ago> Has he read no history? Considering the author is Bob Nystrom, one of the main engineers of Dart, I'd wager the answer is yes.
- munificent 12y ago> one of the main engineers of Dart, I'd wager the answer is yes. I should point out that I'm on Dart, but I'm pretty low on the totem pole. I just happen to write more publicly than many of my teammates. :)
- sz4kerto 12y ago> That's why async I/O is hot right now Well, async I/O is good. However, the reason why it's super hot right now on the internetz is because people don't understand that race conditions and synchronization is something you _cannot avoid_. Your program either needs coordination or not. If it does, then there will be some kind of synchronization used. Dependencies and synchronization is not something that only occurs when accessing shared collections. In any condition, where the semantics of the algorithm requires ordering and/or transactionality and that algorithm is somehow distributed(between threads, processes, machines, you name it) and concurrent, then you will end up using lock/barrier/etc. semantics. No language itself will solve this issue as it stems from the problem you're trying to solve, not from the language constructs. Also, on a side note: I love what Clojure does with transactions and STM, but it essentially converts a problem into something that is easier to handle in 99% of the cases, and hard to handle in the rest. (Transaction rollbacks, etc.) Anyway: every single programmer needs to be comfortable with thread-level concurrency, as you'll face the same problems in on higher abstraction levels where it'll be more difficult to recognize them. He's not saying threads are the solution: he's saying that these 'modern' approaches don't make your life as easy as you would think. Abstracted coordination makes simple programs simpler, but if you don't understand the underlying principles then suddenly your ocean of callbacks will fail somewhere, and you won't understand why.
- jlongster 12y agoHis solution isn't raw OS-level threads. Thread semantics are the solution. It could be greenthreads that all run within the same OS-level thread. Basically, when a function A calls function B, if function B blocks it blocks function A as well. The entire stack blocks on whatever it going on the top frame. I've wondered that myself. node-fibers basically does this, but for some reason it's pretty hated in the JS world.
- xixixao 12y agoI really don't understand this point of the article: I hated the fact that in Java any call might block. To me, this isn't some better abstraction, this is like a language being impure by default: any function can make changes to global state. So actually I preferred seeing the color of the functions - it made the program much more understandable and "safer".
- AgentME 12y ago>Threads is a limited resource. Threads are expensive to create and dispose. Context switches are espensive. ... Languages like Go with green threads don't have those issues. They execute about the same way languages that expose async IO do.
- drostie 12y agoSince he's a Go fan, he might prefer lightweight threads running in an event loop rather than real threads with their context-switches. Moreover his concern is syntactic, not semantic: so maybe he'd like something which "looks thread-like" but "complies-to-CPS" too. Some Microsoft engineers are working on a nice solution to the thread-race-condition problem with a somewhat different approach: pretend your threaded environment is a DVCS. When you want to spawn a new lightweight-thread, think of it as a git clone. It makes its own changes to its own state, then you can eventually pull its changes into the present state -- so you get deterministic threading if you've got a deterministic merge algorithm. http://research.microsoft.com/en-us/projects/revisions/ http://research.microsoft.com/en-us/projects/revisions/
- seanmcdirmid 12y agoIf you are interested in concurrent revisions, you might also be interested in Glitch: http://research.microsoft.com/en-us/people/smcdirm/managedtime.aspx http://research.microsoft.com/en-us/people/smcdirm/managedti... In contrast to Burckhardt et. al's work, Glitch re-executes computations to reach a fixed point (logging side effects so they can be rolled back along the way). This paper compares the various approaches in solving this problem (including concurrent revisions, but also a few others): http://research.microsoft.com/pubs/211297/onward14.pdf http://research.microsoft.com/pubs/211297/onward14.pdf
- drostie 12y agoThis has been a fascinating read, but I worry that there's too much pressure in the paper to view all of these different approaches as somehow "solving the same problem". I'm not sure they do. There is this "whoops, my state updated out from under me" concurrency problem. To steal a metaphor from physics, the problem is that we expect the spacetime to be "locally flat" but to curve at long scales -- similarly we expect the state to somehow be locally private but globally we discover it's shared. The multiple timelines (of operations in various threads) contain updates to the shared state which are noncommutative; when we synchronize we try to throw up these big walls, global across all timelines, across which operations cannot pass. Glitch's approach is to break these threads into commutative-and-noncommutative parts (fixed-points and events). So the focus is not actually on the fixed-points; they can be parallelized without fear because the operations on the state commute. The focus is instead on the events. And there it's not clear that the events solve the concurrency problem at all. (Please don't take that as a criticism; I don't think you were trying to solve this problem. Your approach reminds me a little of Sussman's propagators, and definitely it has some nice implications for live-coding.) Concurrent revisions are a more direct response. The basic insight is that no matter what, "there is one authoritative timeline, let's call it the consumer-timeline, which is how all of these noncommutative events from multiple timelines will actually be ordered." Given that insight, and the need for the state to look locally-private, these explicit joins are an obvious solution. The joins look a little jarring because in the spacetime analogy we're talking about a 'piecewise-smooth' function, so there's a sort of derivative-discontinuity happening here. What would be really interesting is if the shared commutative operations of Glitch could change "piecewise smooth" to "smooth", but I don't think these ideas have that power.
- geofft 12y agoThreadpools. Pin threads to processors. Hardware synchronization extensions. Avoid shared state between threads and use language-level primitives to enforce appropriate locking when needed (this isn't really much harder than language-level primitives to make CPS easy). IOCP. Threadpools and innovative synchronization approaches (RCU) are exactly how the Linux kernel handles IO and interrupts internally. They can be unperformant if used poorly, but they don't have to be.
- sbov 12y agoHe is talking of threads as an abstraction. Not operating system threads, more like green threads. Different languages call it different things, so I'm fine with the word thread. He even explains that he doesn't mean operating system threads, so your response doesn't make complete sense to me. I've always wondered why Joyent built Node.js when they already used Erlang. I've tried to research it but there seems to be no articles about it. It's something I would really like to know because it seems like most people's uses for Node.js could easily be done in Erlang, and they were already using Erlang so did it fall short in other important ways? Or Stackless Python if you don't like goofy languages. Both existed when Node.js first was released. Nowadays Go can fill in many people's use cases too. And I would also argue that green threads are higher level than CPS. So there has to be a reason to use Node.js other than its async stuff.
- bcantrill 12y agoWell, we weren't using Erlang much (and had written very little, if any). And while it's unclear if it's related to Erlang or not, over time our Erlang-based systems have been ripped out of our stack because of their failure to meet our production needs. In particular: Erlang-based systems are fine when they're fine, but undebuggable when they're not. While JavaScript might not be known for its observability, we have been able to advance the state of the art there considerably[1]; at this point there is no question that node.js is much more observable and debuggable in production than Erlang. [1] https://www.joyent.com/developers/node/debug https://www.joyent.com/developers/node/debug
- strictfp 12y agoThe problem is not so much threads as the current implementations of threads. So instead of inventing your own crappy thread-like continuation passing style to circumvent threads, we could be spending time fixing them. Linux used to have huge scalability problems with threads. Not so much any more, but the situation could still be improved. I find the culture of circumventing instead of improving problematic and endemic.
- Dylan16807 12y ago>Threads is a limited resource. Threads are expensive to create and dispose. Context switches are espensive. There is absolutely no reason they have to be. If you have an async callback API, you can plaster over it with green threads and they are very cheap, and don't have to involve any new context switches. >Threads must be synchronized. Threads can have race conditions. You don't have to allow your threads to run concurrently just because you added threads.