4 ms·
Simple to fault, in that channels and Goroutines don’t prevent you from making mistakes the way actors do - ie you can still share state and memory. Go allows f
by sudhirj 9y ago
Simple to fault, in that channels and Goroutines don’t prevent you from making mistakes the way actors do - ie you can still share state and memory. Go allows for the possibility of writing cleanly concurrent code, but you must study and practice.
Using an actor system, though, involves a bit more study with regards to setting things up, but it’s almost impossible to make mistakes - actors simply can’t access each other’s state (maybe some systems allow it, but you’ll have to struggle against the language to make that mistake).
- macintux 9y agoErlang does a great job of protecting data from concurrency problems, but you're still vulnerable to mistakes like deadlock.
- signa11 9y ago> Erlang does a great job of protecting data from concurrency problems, but you're still vulnerable to mistakes like deadlock. without any shared data, and an asynchronous-message-passing style concurrency (i.e sharing memory by communicating, as opposed to communicating by sharing memory) can you please elucidate how we might get into deadlocks ? thanks !
- macintux 9y agoOTP offers two basic messaging options: async or synchronous. The latter is implemented by forcing the caller to wait for the response. If process A sends a synchronous message to B, and B while processing it sends a different synchronous message either directly to A or to another process that eventually calls back to A, you end up in a deadlocked state.
- signa11 9y ago> OTP offers two basic messaging options: async or synchronous. with synchronous messaging it is quite easy to see how deadlocks can happen, without trying too hard. for async messaging, which is what i was referring to, it is quite hard (and or convoluted) to get into that state...
- Jtsummers 9y agoreceive is a blocking action in erlang so something like: loop(State) -> receive msg -> loop(State) end. Will block waiting for `msg` to show up. So if you have two processes that are interacting with eachother and aren't careful in constructing their communication you could end up with something (contrived): loop(Pid) -> receive msg -> Pid ! msg end, loop(Pid). If you have two processes A and B that end up in this same loop but referencing each other, they'd deadlock. Substituting A and B for Pid you'd end up with something like: loop(B) -> % Process A receive msg -> B ! msg end, loop(B). loop(A) -> % Process B receive msg -> A ! msg end, loop(A). Both waiting for `msg` but never sending it to their partner process.
- signa11 9y ago> Both waiting for `msg` but never sending it to their partner process. but then you can 'deadlock' for a single pid as well right ? where you wait for a message which no one is sending...
- sudhirj 9y agoThat wouldn't count as a deadlock. A deadlock implies that it's possible to make a logical determination that the system is permanently stuck, and that state cannot possibly change without external intervention. i.e. a deadlock can only be determined when you look at the system as a whole from the outside and determine that it's permanently stuck.
- signa11 9y ago> That wouldn't count as a deadlock. A deadlock implies that it's possible to make a logical determination that the system is permanently stuck, and that state cannot possibly change without external intervention. i.e. a deadlock can only be determined when you look at the system as a whole from the outside and determine that it's permanently stuck. yes, i know. as i have pointed out elsewhere, with synchronous invocations, it is easy to get into a loop (or deadlock) i.e. pid-a -> pid-b -> pid-c -> pid-a. for the async case, which is what was elucidated by gp, it seems to me that the example is 'deadlocking' only because no one is sending messages expected by the other party...
- lostcolony 9y agoAlso livelocks and race conditions. They're just harder, usually requiring some bad design decisions.
- convolvatron 9y agoyou can voluntarily write Go which doesn't share any state, although clearly if thats an invariant you'd like to keep it would be really nice for the language to enforce it for you. more importantly I've found that as you grow such Go programs, write higher-order actors, and deal with all the error/cleanup cases, the selects start to get really brittle and you end up spending alot of time refactoring them and carefully going over all the edge cases.