Open bhousel opened 3 years ago
Docs:
webworker perf:
mapbox-gl related worker benchmarks:
serialization benchmarks:
I'm really enjoying working with threads.js and have made some small progress on moving some background GeoJSON processing to a worker:
It's looking like avro / avsc is the frontrunner for if we want to pack and larger messages into a Transferable.
Update: this turned out not to be true, not worth a penalty of a few 100 milliseconds just to pack/unpack smaller messages.
I did some testing with moving some pieces of the coreLocations
functionality into a worker. Here's what I learned.
coreLocations
maintains an internal index of all the boundaries/geofences used by iD. This code is used by presets, community index, background imagery, to know where in the world things are valid.
iD uses this code for a lot of things, for example knowing which countries use a VAT ID field, where Aldi Nord vs Aldi Süd operate, and mapping out the Burger King zone of exclusion. These geofences are defined by locationSets and they need to be pieced together soon after iD starts up. Currently, the coreLocations
module will merge and resolve these locationSets in the background during idle times. This works ok - but iD stutters a bit for the first few seconds when it starts up.
This work is 1. time consuming and 2. already asynchronous, so that makes it well suited to move into a web worker.
Here are some things that make web workers hard to work with.
context
, history
, graph
, etc, we really can't do much with actual OSM data without big architectural changes.esbuild
make separate iD.js
and worker.js
bundles. It turns out esbuild
is not great at tree shaking (dead code elimination), so the worker.js
file ended up with all the main thread's imported code. It's just easier to put the worker stuff in a separate file for now, otherwise the worker bundle ends up with all of d3, id-sdk and whatever else.Here's what I did:
coreLocations
into a worker. Wrote a thin proxy that passed messages back and forth with postMessage. This seemed to work ok except..locationManager.locationsAt()
was no longer synchronous. This is the code that determines which locations a preset or field is available. This means preset matching is no longer synchronous and all kinds of stuff throughout the code just won't work, so...locationsAt()
synchronous? Only by having a copy of the location index on the main thread...These are interesting because iD first merges the core presets (only 9 locationSets), then fetches the NSI presets (15839 locationSets), then does an unnecessary merge (0 locationSets). So we can see how much different sizes of messages cost.
TODO: going to try the avro library and see if I can get those main thread unpack times down.. Update:
) It looks like the pack/unpack times went up a bit, (though the sizes of the buffers transferred is a lot lower), so Avro looks to not be as much of a win as I had hoped it would be.
We can move a bunch of our low priority but main-thread-blocking tasks onto web workers for better performance. I'm planning some work on this for the next version.