parallel: more efficient Run

We refactor Run to make it faster and more memory efficient.

Also added some benchmarks to verify this:

benchmark                old ns/op     new ns/op     delta
BenchmarkRunSingle       3163          1933          -38.89%
BenchmarkRun1000p100     714010        379910        -46.79%

benchmark                old allocs     new allocs     delta
BenchmarkRunSingle       10             3              -70.00%
BenchmarkRun1000p100     3007           3              -99.90%

benchmark                old bytes     new bytes     delta
BenchmarkRunSingle       412           240           -41.75%
BenchmarkRun1000p100     48394         240           -99.50%

I used the benchmarks that I added elsewhere in this PR.
The improvement was <2% in both benchmarks. I'm not
surprised - the mutex will be very fast in the uncontested case,
and Do is usually not called concurrently (and certainly won't
be in the situation we care about currently).