This is a bit of low-hanging fruit, but we currently define Parallel[F] given GenSpawn[F, _] in terms of the following construction:
final override def map2[A, B, Z](fa: ParallelF[F, A], fb: ParallelF[F, B])(
f: (A, B) => Z): ParallelF[F, Z] =
ParallelF(
F.both(ParallelF.value(fa), ParallelF.value(fb)).map { case (a, b) => f(a, b) }
)
That's cool but there's a lot of unnecessary boxing in here, both in both and in racePair underneath. We can actually do a lot better given GenConcurrent[F, _], which will be the case quite a lot of the time in practical code. However, rather than creating some sort of sneaky implicit prioritization thing, I think the right approach here is probably to add a mapBoth function (feel free to bikeshed the name) to GenSpawn, then override it in GenConcurrent with a more efficient implementation in terms of Fiber and Deferred.
Overall this probably sounds a lot more intimidating of an enhancement than it actually is. Tldr, add the following to GenSpawn:
def mapBoth[A, B, C](fa: F[A], fb: F[B])(f: (A, B) => F[C]): F[C] = ???
Delegate the implementation to both in GenSpawn, but then override that implementation in GenConcurrent with something implemented in terms of Fiber and Deferred. The results should be a noticeable improvement in performance of the par operators.
This is a bit of low-hanging fruit, but we currently define
Parallel[F]givenGenSpawn[F, _]in terms of the following construction:That's cool but there's a lot of unnecessary boxing in here, both in
bothand inracePairunderneath. We can actually do a lot better givenGenConcurrent[F, _], which will be the case quite a lot of the time in practical code. However, rather than creating some sort of sneaky implicit prioritization thing, I think the right approach here is probably to add amapBothfunction (feel free to bikeshed the name) toGenSpawn, then override it inGenConcurrentwith a more efficient implementation in terms ofFiberandDeferred.Overall this probably sounds a lot more intimidating of an enhancement than it actually is. Tldr, add the following to
GenSpawn:Delegate the implementation to
bothinGenSpawn, but then override that implementation inGenConcurrentwith something implemented in terms ofFiberandDeferred. The results should be a noticeable improvement in performance of theparoperators.