TaskGroup and Parallelism

Rob's test proves that withTaskGroup is now well optimized and does not have an inherently high overhead. His example is the perfect way to measure the inherent overhead: We have plenty of performance cores (16 of Ultra vs 2 of A15) and a computation-intensive code that does not block for I/O or other system calls and you see the perfect 16x performance boost vs a single core.

In Rob's scenario, the other tasks that demand CPU time are practically negligible compared to the actual computation load of the test. But in the constrained environment of A15 (core count and default power policy), you can't neglect other factors, especially I/O, system calls, and the scheduling policy. The very name of concurrentPerform shows that its execution policy prefers parallelism.

On the other hand, the default executor that is handling Swift concurrency is balanced for the best overall experience (which includes battery life and the heat generated on the phone surface, among other things). If you want maximum parallelism at any cost, still concurrentPerform is the way to go.

When you have plenty of performance cores at your disposal, the result of the default executor becomes almost identical to concurrentPerform. It does not have anything against parallelism, the only difference is that it puts a higher priority on other factors.

Also, note that your example is I/O bound. Unfortunately, we don't have true async I/O in the Darwin kernel. The only way to get better I/O performance is to throw more threads at it. But more threads will increase memory and power consumption. Darwin's kernel development has been very stagnant for many years now. A true async subsystem is sorely needed.

6 Likes