From 328991d22b9a27b4e417151c41dedae8c46d7115 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Sat, 6 Aug 2016 01:20:08 -0400 Subject: [PATCH] Add minimal worker pool --- debug/shared_workers.html | 122 ++++++++++++++++++++++++++++++++++ js/util/dispatcher.js | 11 +-- js/util/worker_pool.js | 35 ++++++++++ test/js/source/worker.test.js | 76 ++++++++++++++++----- 4 files changed, 221 insertions(+), 23 deletions(-) create mode 100644 debug/shared_workers.html create mode 100644 js/util/worker_pool.js diff --git a/debug/shared_workers.html b/debug/shared_workers.html new file mode 100644 index 00000000000..e36330e7fa7 --- /dev/null +++ b/debug/shared_workers.html @@ -0,0 +1,122 @@ + + + + Mapbox GL JS debug page + + + + + + + + +
+
+
+
+ +
+
+
+
+ +
+ + + + + + + + + + diff --git a/js/util/dispatcher.js b/js/util/dispatcher.js index cc7a9206e9b..51e9fa3b41f 100644 --- a/js/util/dispatcher.js +++ b/js/util/dispatcher.js @@ -1,10 +1,11 @@ 'use strict'; +var WorkerPool = require('./worker_pool'); var util = require('./util'); var Actor = require('./actor'); -var WebWorker = require('./web_worker'); module.exports = Dispatcher; +Dispatcher.workerPool = new WorkerPool(); /** * Responsible for sending messages from a {@link Source} to an associated @@ -17,8 +18,9 @@ function Dispatcher(length, parent) { this.actors = []; this.currentActor = 0; this.id = util.uniqueId(); + var workers = Dispatcher.workerPool.acquire(this.id, length); for (var i = 0; i < length; i++) { - var worker = new WebWorker(); + var worker = workers[i]; var actor = new Actor(worker, parent, this.id); actor.name = "Worker " + i; this.actors.push(actor); @@ -66,9 +68,8 @@ Dispatcher.prototype = { }, remove: function() { - for (var i = 0; i < this.actors.length; i++) { - this.actors[i].target.terminate(); - } + Dispatcher.workerPool.release(this.id); this.actors = []; } }; + diff --git a/js/util/worker_pool.js b/js/util/worker_pool.js new file mode 100644 index 00000000000..246cf80b1b7 --- /dev/null +++ b/js/util/worker_pool.js @@ -0,0 +1,35 @@ +'use strict'; + +var assert = require('assert'); +var WebWorker = require('./web_worker'); + +module.exports = WorkerPool; + +function WorkerPool() { + this.workers = []; + this.active = {}; +} + +WorkerPool.prototype = { + acquire: function (mapId, workerCount) { + this._resize(workerCount); + this.active[mapId] = workerCount; + return this.workers.slice(0, workerCount); + }, + + release: function (mapId) { + delete this.active[mapId]; + if (Object.keys(this.active).length === 0) { + this.workers.forEach(function (w) { w.terminate(); }); + this.workers = []; + } + }, + + _resize: function (len) { + assert(typeof len === 'number'); + while (this.workers.length < len) { + this.workers.push(new WebWorker()); + } + } +}; + diff --git a/test/js/source/worker.test.js b/test/js/source/worker.test.js index dcea5af78f6..2f9919553fd 100644 --- a/test/js/source/worker.test.js +++ b/test/js/source/worker.test.js @@ -26,7 +26,7 @@ test('before', function(t) { test('load tile', function(t) { t.test('calls callback on error', function(t) { var worker = new Worker(_self); - worker['load tile']({ + worker['load tile'](0, { source: 'source', uid: 0, url: 'http://localhost:2900/error' @@ -42,25 +42,25 @@ test('load tile', function(t) { test('set layers', function(t) { var worker = new Worker(_self); - worker['set layers']([ + worker['set layers'](0, [ { id: 'one', type: 'circle', paint: { 'circle-color': 'red' } }, { id: 'two', type: 'circle', paint: { 'circle-color': 'green' } }, { id: 'three', ref: 'two', type: 'circle', paint: { 'circle-color': 'blue' } } ]); - t.equal(worker.layers.one.id, 'one'); - t.equal(worker.layers.two.id, 'two'); - t.equal(worker.layers.three.id, 'three'); + t.equal(worker.layers[0].one.id, 'one'); + t.equal(worker.layers[0].two.id, 'two'); + t.equal(worker.layers[0].three.id, 'three'); - t.equal(worker.layers.one.getPaintProperty('circle-color'), 'red'); - t.equal(worker.layers.two.getPaintProperty('circle-color'), 'green'); - t.equal(worker.layers.three.getPaintProperty('circle-color'), 'blue'); + t.equal(worker.layers[0].one.getPaintProperty('circle-color'), 'red'); + t.equal(worker.layers[0].two.getPaintProperty('circle-color'), 'green'); + t.equal(worker.layers[0].three.getPaintProperty('circle-color'), 'blue'); - t.equal(worker.layerFamilies.one.length, 1); - t.equal(worker.layerFamilies.one[0].id, 'one'); - t.equal(worker.layerFamilies.two.length, 2); - t.equal(worker.layerFamilies.two[0].id, 'two'); - t.equal(worker.layerFamilies.two[1].id, 'three'); + t.equal(worker.layerFamilies[0].one.length, 1); + t.equal(worker.layerFamilies[0].one[0].id, 'one'); + t.equal(worker.layerFamilies[0].two.length, 2); + t.equal(worker.layerFamilies[0].two[0].id, 'two'); + t.equal(worker.layerFamilies[0].two[1].id, 'three'); t.end(); }); @@ -68,25 +68,65 @@ test('set layers', function(t) { test('update layers', function(t) { var worker = new Worker(_self); - worker['set layers']([ + worker['set layers'](0, [ { id: 'one', type: 'circle', paint: { 'circle-color': 'red' } }, { id: 'two', type: 'circle', paint: { 'circle-color': 'green' } }, { id: 'three', ref: 'two', type: 'circle', paint: { 'circle-color': 'blue' } } ]); - worker['update layers']({ + worker['update layers'](0, { one: { id: 'one', type: 'circle', paint: { 'circle-color': 'cyan' } }, two: { id: 'two', type: 'circle', paint: { 'circle-color': 'magenta' } }, three: { id: 'three', ref: 'two', type: 'circle', paint: { 'circle-color': 'yellow' } } }); - t.equal(worker.layers.one.getPaintProperty('circle-color'), 'cyan'); - t.equal(worker.layers.two.getPaintProperty('circle-color'), 'magenta'); - t.equal(worker.layers.three.getPaintProperty('circle-color'), 'yellow'); + t.equal(worker.layers[0].one.getPaintProperty('circle-color'), 'cyan'); + t.equal(worker.layers[0].two.getPaintProperty('circle-color'), 'magenta'); + t.equal(worker.layers[0].three.getPaintProperty('circle-color'), 'yellow'); t.end(); }); +test('update layers isolates different instances\' data', function(t) { + var worker = new Worker(_self); + + worker['set layers'](0, [ + { id: 'one', type: 'circle', paint: { 'circle-color': 'red' } }, + { id: 'two', type: 'circle', paint: { 'circle-color': 'green' } }, + { id: 'three', ref: 'two', type: 'circle', paint: { 'circle-color': 'blue' } } + ]); + + worker['set layers'](1, [ + { id: 'one', type: 'circle', paint: { 'circle-color': 'red' } }, + { id: 'two', type: 'circle', paint: { 'circle-color': 'green' } }, + { id: 'three', ref: 'two', type: 'circle', paint: { 'circle-color': 'blue' } } + ]); + + worker['update layers'](1, { + one: { id: 'one', type: 'circle', paint: { 'circle-color': 'cyan' } }, + two: { id: 'two', type: 'circle', paint: { 'circle-color': 'magenta' } }, + three: { id: 'three', ref: 'two', type: 'circle', paint: { 'circle-color': 'yellow' } } + }); + + t.equal(worker.layers[0].one.id, 'one'); + t.equal(worker.layers[0].two.id, 'two'); + t.equal(worker.layers[0].three.id, 'three'); + + t.equal(worker.layers[0].one.getPaintProperty('circle-color'), 'red'); + t.equal(worker.layers[0].two.getPaintProperty('circle-color'), 'green'); + t.equal(worker.layers[0].three.getPaintProperty('circle-color'), 'blue'); + + t.equal(worker.layerFamilies[0].one.length, 1); + t.equal(worker.layerFamilies[0].one[0].id, 'one'); + t.equal(worker.layerFamilies[0].two.length, 2); + t.equal(worker.layerFamilies[0].two[0].id, 'two'); + t.equal(worker.layerFamilies[0].two[1].id, 'three'); + + + t.end(); +}); + + test('after', function(t) { server.close(t.end); });