comlink icon indicating copy to clipboard operation
comlink copied to clipboard

Use a single "message" event listener to dispatch received messages

Open achim-k opened this issue 1 year ago • 8 comments

From #649:

We make heavy use of Comlink for our WebWorker communication. On some recent profiling traces I noticed a hot-path on the "addEventListener" line.

292389350-2052be72-8671-4e20-9e06-fef0a30cb420

While its hard to say exactly how the event listeners are stored, most implementations I've seen for such interfaces involve storing them in an array and removing the listener equally requires adjusting an array. The existing logic also creates two closures - one for the Promise (which is unavoidable from what I can tell), and another for the event listener. As it was suggested in https://github.com/GoogleChromeLabs/comlink/issues/647 there is a potential for improvement by using a single "message" event listener and doing the dispatch manually by looking up the resolve functions in a Map.

This definitely reduces the runtime cost of the requestResponseMessage call itself - though there's still cost to new Promise and the closure. There's a shifted cost to the ID lookup on the map though in my profiling that did not show up as a hot path item.

Conceptually using a map for the lookup and one handler seems like it should perform better but if folks have some ideas on how to more robustly benchmark this PR that would be helpful.

This PR is similar to #649 and #651 but avoids that references to the resolve functions or the endpoint are kept in memory.

The performance impact of this PR gets more noticeable the more parallel requests are made: boxcompare

See also https://github.com/GoogleChromeLabs/comlink/pull/651#issuecomment-1899065317

achim-k avatar Jan 18 '24 22:01 achim-k

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

google-cla[bot] avatar Jan 18 '24 22:01 google-cla[bot]

This change had a huge impact on my work with a physics library. I am calling a function on main thread to add physics bodies in the worker thread. Originally it was a huge hot path, because I was stress testing creating 5000 bodies in one 16ms tick.

I thought I would have to instead batch up the commands and parameters and send over in one message (which still might be a good idea), instead I can now continue to use the comlink proxy for the function. Nice work.

I am now using the foxglove fork for my project to pick up the other nice to haves like faster id generation.

MikalDev avatar Mar 02 '24 03:03 MikalDev

@achim-k Thank you for this change! I think the performance improvements are great. Do you still need to follow up on something or at this point are just waiting for the final PR approval?

lvivski avatar Mar 26 '24 18:03 lvivski

@achim-k Thank you for this change! I think the performance improvements are great. Do you still need to follow up on something or at this point are just waiting for the final PR approval?

This is just waiting for the final approval. We are already using this in production for a couple of months, without issues.

achim-k avatar Mar 26 '24 18:03 achim-k

@surma is this PR still interesting from the maintainer's perspective? I understand that you might have different opinions on how this should be implemented. I think this is a useful change for high-throughput applications.

lvivski avatar Mar 26 '24 19:03 lvivski