Concurrency Solutions

time to read 4 min | 611 words

I am not sure why, but recently I have became interested in concurrency again. I blogged about both the pipeline and the tasks scheduling approaches recently, and I was repeatedly pointed to Retlang, Parallel FX and the Concurrency and Coordination Runtime.

I thought that it would be interesting to compare those approaches.

The pipeline

The pipeline can be easily parallelized, because there is an explicit handoff of objects as they pass from one stage of the pipeline to another. The only synchronization needed for this would be in terms of passing the objects between the stages.

Task Scheduling

Task scheduling is interesting, mainly because the way it operates is fits the concurrent model so nicely. You execute something, you wait for it, you don't take any resources while you do this. To me, it looks like quite a natural way of programming, especially with the ability to wait on other tasks.

Retlang

Retlang's concurrency model is based on message passing. As such, it is ideally suited to supporting cross thread communication, event driven systems, pipeline processing, etc. Bind Retlang with the Task Scheduling solution, and you are nearly at Erlang's capabilities.

Parallel FX

I get to run things in parallel, that is about it. The ability to scale a for loop to the number of processors on the machine is nice, but I am seeing it as a low level utility more than anything else. PLinq is much more interesting.

Then again, I am currently in search for higher level concurrency solutions than what Parallel FX supply.

Concurrency and Coordination Runtime

This looks a lot more like what I had in mind. The concurrency primitive that we have here are high level enough to be really useful, and it looks like it has implemented the same ideas that I had, both message passing and task based. I haven't played with it, just read the docs, so I am not sure how useful this really is.

State

The real problem with concurrency is state. Erlang gets away with dealing with it because it has no mutable state. In most imperative languages, we have to deal with this somehow.

The usual answer for that is don't share state. The pipeline example is a good one, you don't get two processes dealing with the same object at the same time.

In my task scheduling code, I am ensuring that a task can run on a single thread at a time (but not that it run on the same thread all the time. This should take care of most state issues, since as long as you keep to your own instance, you are safe. If you start passing around mutable variables, then you need to thread more carefully.

Ordering

Another issue that you have with concurrency is that you usually have some requirements about in what order you want to deal with operations. You can't really approve an order before it was created, now can you?

Different approaches for concurrency has different guarantees in regards to ordering. Retlang will always preserve ordering, which make some things extremely simple. My Task Scheduling library will not preserve ordering (it will schedule the first task that is ready to go), and Parallel FX doesn't preserve ordering unless you explicitly request it (couldn't find out about the CCR).

An interesting observation about the task scheduling library, it doesn't really need ordering, because of the way we yield in the method, we can get away with just waiting for the values to be completed.

I don't think that there is a right approach, but I strongly lean toward tasks and message passing as a default concurrency approach.