# Parallel execution on CPU

i developed following code:

processSegment[start_, end_] :=
Module[{segmentVector, segmentNormal},
segmentVector = end - start;
segmentNormal = Reverse[segmentVector] {-1, 1} Sqrt[3]/6;
{Line[{start, start + segmentVector/3}],
Line[{start + segmentVector/3,
start + segmentVector/2 + segmentNormal}],
Line[{start + segmentVector/2 + segmentNormal,
start + 2 segmentVector/3}],
Line[{start + 2 segmentVector/3, end}]
}
]

kochkurve[n_Integer?NonNegative] :=
Show[Graphics[
Nest[ (#1 /.
Line[{start_, finish_}] :> processSegment[start, finish]) &,
{Line[{{0, 0}, {1, 0}}]},
n]],
AspectRatio -> Automatic, PlotRange -> All]

kochkurve[9]


The matter is, that this code switches the CPU cores very slow (due to the task manager) if ever. So usually one CPU works for about 5 secs the other one do nothing.

Even when i use the integrated Parallelize function there is no change in the workload. Is there any chance to upgrade the workload and if yes, how? And when not, why is that not possible?

• Strongly related: mathematica.stackexchange.com/q/1883/57 – Sjoerd C. de Vries Jun 9 '15 at 18:02
• Thank you for the link. But i still have no idea how i could integrate the seperate kernel task into my code. Kernels are not the problem, i have 640 available. So could you give me please a hint how to manage this? – PowerFlower Jun 11 '15 at 14:42
• See answer below. – Sjoerd C. de Vries Jun 11 '15 at 15:57

As you have written it, it is not easily parallelizable. There is just a single task that consists of a Nest. Each iteration in the Nest needs the result of the previous step and that should be available at the start of the next iteration. I don't see how you could parallelize that without a lot of slow inter-process communication.

The best way to parallelize this would be (I think) to let it run until a certain depth (for instance 4 in your case) and let the resulting line elements (256 for n=4) be operated on by 256 separate kernels, which, with your 640 available kernels, shouldn't be a problem.

Changing the code a bit (removing line drawing from processing steps, adding the starting segment as a argument):

ClearAll[kochkurve, processSegment]

kochkurve[n_Integer?NonNegative, {initStart_, initFinish_}] :=
(Partition[#, 2] &)@(Partition[#, 2] &)@
Flatten@Nest[(#1 /. {start_, finish_} :>
processSegment[start, finish]) &, {{initStart, initFinish}}, n]

processSegment[start_, end_] := Module[{segmentVector, segmentNormal},
segmentVector = end - start;
segmentNormal = Reverse[segmentVector] {-1, 1} Sqrt[3]/6;
{{start, start + segmentVector/3}, {start + segmentVector/3,
start + segmentVector/2 + segmentNormal}, {start +
segmentVector/2 + segmentNormal,
start + 2 segmentVector/3}, {start + 2 segmentVector/3, end}}]

Line /@ ParallelMap[(kochkurve[5, #] &),  kochkurve[4, {{0, 0}, {1, 0}}]] // Graphics


Tasks could be launched by ParallelSubmit and started with WaitAll as well.

Line /@ WaitAll[ParallelSubmit[(kochkurve[5, #])] & /@
kochkurve[4, {{0, 0}, {1, 0}}]] // Graphics


Most mortals probably want the rightmost kochkurve to be only 1 level deep (4 segments and hence 4 kernels).

• Thats just awesome. Thank you. This nearly halves the the calculation time. – PowerFlower Jun 11 '15 at 16:42
• With so many kernels available to you that's a bit disappointing, though I get only a 25% improvement. It may help to play with the balance between the first and second kochkurve contribution. I find it helps if the rightmost kochkurve yields somewhat more initial pieces than kernels. – Sjoerd C. de Vries Jun 11 '15 at 17:39