Concurrency can result in increased maintenance costs and complexity.
Concurrency is also not more efficient on a single core.
Concurrency can help with latency and response time.
In embedded systems in particular, there is an over-use of concurrency which often results in bloated, complex code.
Concurrency can be more efficient even on a single core. When blocking synchronous I/O is involved, concurrency may help saturate the bandwidth with multiple in-flight requests.
Otherwise, no.
(and in general, people just throw concurrency at the problem instead of analysing whether they are in fact I/O bound or CPU bound).
(Downvoted why??)
Concurrency is usually not a feature of the algorithm but a feature of the problem domain. If you have many requests coming in at the same time, all competing for a limited amount of computational resources -- you have concurrency.
How you handle it is a different matter. You can decide to handle the requests one by one, but then, by Little's law, your throughput would be very low, and your server will crash if the rate of requests is over some small limit (which depends on the time it takes to service each request).
Concurrency improves performance when a process accesses both the same computational resource and some other high-latency sharable resource.
But in fact concurrency is inevitable in absence of OS threads that can be blocked (another potential clusterfuck) or of some form of continuations support, because it is a direct consequence of asynchrony.
And asynchrony isn't avoidable, all you can do is to find abstractions that make it more deterministic.
We are all taught from uni about how concurrency is implemented and most applications use concurrency as a design-tool to decompose a problem into its functions.
Unfortunately, this tends to produce a sub-optimal result as the inefficiencies become visible on small embedded/real-time systems.
Its difficult to give any general advice, but have a look at real-time analysis to get an idea of the real issues.... and don't blindly throw tasks at a problem when a simple superloop is more efficient/simple/maintainable.
This isn't a hard and fast rule. There is overhead to parallelism.
For I/O bound code, concurrency can give you some benefit.
...but in general, people do not analyse this before throwing tasks at a problem.
When I grew up to be a programmer, never had much problems with concurrent stuff.
IMO designing concurrent programs is conceptually similar to building complex high-throughput low latency railway networks in the game.
You can serialize the transitions if you want, but that usually costs performance. This is especially true for distributed parallel computing, where the state is also distributed.
This is our partial correctness property
PartialCorrectness ≜ AllDone ⇒ ∃ p ∈ ProcSet : y[p] = 1
And this is the inductive invariant: Inv ≜ PartialCorrectness
∧ ∀ p ∈ ProcSet : pc[p] ≠ "Line1" ⇒ x[p] = 1
We need to show that Inv implies PartialCorrectness (trivial), that Inv holds in the initial state, and that if it holds in any state s, then it holds in any possible consecutive step s'. It's easy to see that it holds in the initial state. Now, let's assume it holds in s, and prove for s'. To make this transition, some process p either executes line 1 or executes line 2. If it executes 1, then PartialCorrectness doesn't change because no new process is done. The second conjunct holds because we've just left line 1 and x has been assigned (by the definition of line 1). If we are currently in line 2, the second conjunct of the invariant doesn't change. By the definition of this action, we'll be done. Here we have two cases, either we set y to 1, or we set y to zero. If we set y to 1, we're done and PartialCorrectness holds. If we set y to 0 then by the assumption of the invariant, the process we depend on must not be done, hence AllDone is false, and PartialCorrectness holds. QED.