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);
or a 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 for
if 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.
-Brad