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 just tried out this:

	func (r *Run) Do(f func() error) {
		select {
		case r.work <- f:
			return
		default:
		}
		running := atomic.LoadInt64(&r.running)
		if running < r.max {
			newRunning := atomic.AddInt64(&r.running, 1)
			if newRunning <= r.max {
				go r.runner()
			} else {
				// Another concurrent Do has taken our slot,
				// and there are no more slots left, so forget about our add.
				atomic.AddInt64(&r.running, -1)
			}
		}
		r.work <- f
	}

and got just 1.2% speed improvement. That's not worth the additional difficulty of reasoning about the code, IMHO.