-
Notifications
You must be signed in to change notification settings - Fork 1.3k
MGLComputedShapeSource/CustomGeometrySource.java shouldn't create thread pools #11895
Description
The core CustomGeometrySource is configured with a "fetch tile function" that glues out into the platform-specific wrappers (and eventually the user-provided custom implementation). The darwin implementation of this function is in MGLComputedShapeSource.mm and the Android implementation is in CustomGeometrySource.java. Both implementations follow a similar pattern:
- Wrap the tile ID up in a "request" object
- Pass that request object off to be run on a shared pool of 4 worker threads
- When processing a request on the worker thread, synchronously call into the user-provided custom source to get data (
id<MGLComputedShapeSourceDataSource>on darwin,GeometryTileProvideron Android), and then once the synchronous call returns, queue an asynchronoussetTileDatacallback that feeds back into the coreCustomGeometrySource
I think this model would make sense if the primary job of the user-provided tile provider was to run some computationally expensive operation, but it doesn't seem to me like a very good fit for the case where the tile provider's job involves asynchronously requesting resources itself. Because the provider doesn't have access to a callback, it needs to block on asynchronous requests, which is an awkward interface and also opens the potential for clogging up the 4 worker threads with blocking requests. Also, this forces the provider to support synchronized cross-thread access to itself (a bit of an anti-pattern), even when it's not necessary.
I think it would be better if we leave concurrency choices to the user, so for instance GeometryTileProvider::getFeaturesForBounds would take a callback as an argument (some kind of wrapper on the core ActorRef that's being used for the underlying callback). Then, for someone implementing GeometryTileProvider:
- If the computation is simple, just do it synchronously and call the callback immediately.
- If the computation depends on an asynchronous resource like a network or database request, go ahead and make the request and pass the callback through. Don't worry about threads, that's an implementation detail of your network/database layer.
- If you actually have a lot of CPU work to do and you want to fire up worker threads and give them a queue of tasks, fine go ahead and do it, and it's on you to think about how to manage concurrency.