Hi Damian —
In your case, where
c has already been initialized before encountering these loop idioms, the first two approaches should be more or less equivalent in terms of performance, as should the final two. If you were to see otherwise in practice, that's something we'd be interested in hearing about.
In more detail, the first two loops should result in multicore parallel execution, whereas the last two will necessarily be serial by virtue of the
for loop. I'm assuming in the following that
someFunc() is simple and side-effect free such that calling it multiple times in parallel is safe and would not results in synchronization.
For large values of
n, I'd typically pick one of the first two to get the benefits of parallelism. A few other ways to write it with parallelism would be to use promotion, like so:
c = someFunc(c);
forall expression, like:
c = forall i in 0..<n do someFunc(c[i]);
Just in case it's unclear
[i in 0..<n] is shorthand for
forall i in 0..<n for a range iterand like this. More generally,
[i in expr] means
forall i in expr when
expr supports a parallel iterator and
foreach i in expr when it does not.
A reason to pick one of the latter two serial loops would be if
n was sufficiently small that you thought spinning up tasks and dividing work across cores was overkill for this computation. As you note, though, falling back to a
foreach rather than a
for could be beneficial if there was a chance that
someFunc() was amenable to vectorization, in which case I'd write:
foreach i in 0..<n do c[i] = someFunc(c[i]);
Generally speaking, there should only be upside to using a
foreach instead of a
someFunc() is parallel-safe, as I'm assuming here.
When in doubt, I'd typically use one of the parallel versions (and specifically, the promoted version for elegance), following an "express all parallelism" philosophy.