6 ms·
> Java threads work everywhere That depends how you define "work". Java has a decent concurrency library such that if you have a limited-scope project implemen
by brlewis 7y ago
> Java threads work everywhere
That depends how you define "work". Java has a decent concurrency library such that if you have a limited-scope project implemented by 1 or 2 highly-skilled programmers, you stand a good chance of avoiding thread safety issues. But as the project grows, the probability of thread safety issues approaches 1.
> Event driven programming has also become threaded, this is how the whole reactive family of frameworks, node.js, etc, handle parallelism.
Event-driven programming is way less painful than Java threads. With threads, in every place you mutate anything you have to ask yourself, "what happens if my thread is preempted here?" With event-driven programming you only do that sort of thinking in places where you see the `await` keyword.
- trhway 7y ago>Event-driven programming is way less painful than Java threads. With threads, in every place you mutate anything you have to ask yourself, "what happens if my thread is preempted here?" in 23 years programming Java (and in the all places where i've worked having been recognized as local expert on threads and synchronization, incl. in the current very large C++ platform project) i have never asked myself that question in the context of the mutation of data.
- plapetomain 7y agoWell you either did ask that question and answered it by using appropriate locking and concurrent data structures (which is basically implicitly asking and addressing that question..) or you wrote a lot of crash prone shitty software. Which one was it?
- trhway 7y agoLocking isn't about preemption. You can have a system without preemption and still have to use the locks and other concurrent primitives.
- deleted 7y ago[deleted]
- kstenerud 7y agoWhat purpose would locks and concurrent primitives have in a system where running code is not preempted?
- trhway 7y agoIn addition to parallel in all senses/levels systems mentioned by the other commenter, another example would be a truely single threaded hardware with cooperative or even sequential multithreading where you'd use locking/etc. to safeguard your memory model invariants against for example compiler, JIT and hardware optimization shenanigans.
- StillBored 7y agoTo guarantee two different threads don't try to simultaneously mutate (or in some cases access) shared resources.
- lowbloodsugar 7y agoNot sure why the downvotes. If a system has enough CPUs, threads might never be preempted, and yet we must still use locks or concurrent primitives if we are sharing resources across multiple threads. I don't think I've actually thought about preemption explicitly since the Nintendo64 days when thread priorities figured into our locking strategy. But then we'd also re-implemented the scheduler and, at times, turned off the official OS to go do something we needed to do without interruption. So, like I said, preemption not high on my radar these days, as it falls under the general category of "concurrency". Even an iPhone has 4 CPUs.
- samatman 7y agoThe question shouldn't have been about preëmption, but rather, "what if some other thread mutates my data here?" The effect is much the same, whether the race is caused by task scheduling, or just because another core got there first.
- pmarreck 7y ago> But as the project grows, the probability of thread safety issues approaches 1. This is exactly why I run unit tests concurrently (other than the speed boost), and try to write the tests (and the code) so that it won't break when run concurrently (like inserting something into a DB and then assuming success only if the count has gone up by exactly 1).
- brlewis 7y agoAre you saying that concurrency issues can reliably be found via testing?
- pmarreck 7y agoWell, they can't be deterministically found since process scheduling is not deterministic (notable exception: Haskell, I believe, has a way to do deterministic concurrent scheduling!), but I have definitely seen fails that only crop up when the suite is run concurrently, and it usually turns out that the code failing in those circumstances has made assumptions about application state that do not hold true in a concurrent context
- btilly 7y agoOK, intermittently your test suite fails nondeterministically 0.01% of the time. Do you imagine that this will be sufficient to find which of the last thousand commits introduced the bug? I would recommend using specialized tools for the task like Intel's Thread Inspector or Coverity's Helgrind.
- pmarreck 7y agoOr one could simply try very hard not to mutate any state that is available to another process and corral all such code that requires doing so (which most of the time ends up being only a small portion of the code; the rest can be designed functionally, just passing values in and back out with no other side-effects) into a thin I/O layer, which is (I believe) the Hexagonal Architecture and is explained quite well by Gary Bernhardt here: https://www.destroyallsoftware.com/talks/boundaries https://www.destroyallsoftware.com/talks/boundaries
- pierrebai 7y agoThat may be true in some language, but it is not generally true. The awaited task can run in parallel and both are only re-sync when you use the result. Thus anything can also be mutated in parallel with await/async style of programming.
- oppositelock 7y agoYou can write horrible event driven code. For example, do your events need to talk to a database? Right there, you've got a synchronization point. Thinking about asynchronous behavior is always tricky, and code designed to run on threaded systems isn't generally arbitrary code with locks thrown into it the mix, you strive to write the largest possible reentrant sections, and only lock where you have to, and as infrequently as possible. With reentrant code, it doesn't matter where you get preempted.
- lmm 7y ago> For example, do your events need to talk to a database? Right there, you've got a synchronization point. Not if you do it right. Interacting with sync-only systems from async systems is a problem, but it's not fair to blame that on async - if you make the whole system work async, you don't have that problem.
- adev_ 7y ago> Event-driven programming is way less painful than Java threads. With threads, in every place you mutate anything you have to ask yourself, "what happens if my thread is preempted here?" Event-driven programming is a different pain in the ass but still a pain in the ass. The current status of the Web speaks for itself: it's event-driven based JavaScript, and it's full of state/transitions bugs everywhere. In event driven you trade concurrent r/w access issues for a loosing execution contexts issues and out of order issues. The result is often a mess of spaghetti callback close to unreadable. The less worst of the world might be simply a proper coroutine system, which seems to come to almost every programming language after 30 years of existence
- Bjartr 7y ago> That depends how you define "work". I don't disagree with what you've said, I just wanted to chime in that in the context of the conversation to this point the definition is something in the ballpark of "are available cross-platform without jumping through hoops".
- brlewis 7y agoI was replying in the context of "This paper came at a time when threads were really painful to work with," which seemed to imply that they're no longer really painful to work with.