render.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. export const render = (function() {
  2. let _IDs = 0;
  3. class PWorker {
  4. constructor(s) {
  5. this._worker = new Worker(s);
  6. this._worker.onmessage = (e) => {
  7. this._OnMessage(e);
  8. };
  9. this._resolve = null;
  10. this._id = _IDs++;
  11. }
  12. _OnMessage(e) {
  13. const resolve = this._resolve;
  14. this._resolve = null;
  15. resolve(e.data);
  16. }
  17. get id() {
  18. return this._id;
  19. }
  20. sendAsync(s) {
  21. return new Promise((resolve) => {
  22. this._resolve = resolve;
  23. this._worker.postMessage(s);
  24. });
  25. }
  26. }
  27. class PWorkerPool {
  28. constructor(sz, entry) {
  29. this._workers = [...Array(sz)].map(_ => new PWorker(entry));
  30. this._free = [...this._workers];
  31. this._busy = {};
  32. this._queue = [];
  33. }
  34. get length() {
  35. return this._workers.length;
  36. }
  37. Broadcast(msg) {
  38. return Promise.all(this._workers.map(w => w.sendAsync(msg)));
  39. }
  40. Enqueue(workItem) {
  41. return new Promise(resolve => {
  42. this._queue.push([workItem, resolve]);
  43. this._PumpQueue();
  44. });
  45. }
  46. _PumpQueue() {
  47. while (this._free.length > 0 && this._queue.length > 0) {
  48. const w = this._free.pop();
  49. this._busy[w.id] = w;
  50. const [workItem, workResolve] = this._queue.shift();
  51. w.sendAsync(workItem).then((v) => {
  52. delete this._busy[w.id];
  53. this._free.push(w);
  54. workResolve(v);
  55. this._PumpQueue();
  56. });
  57. }
  58. }
  59. }
  60. const _POOL = new PWorkerPool(
  61. navigator.hardwareConcurrency, 'genetic-worker.js');
  62. return {
  63. setup: function(srcData) {
  64. const setupMsg = {
  65. action: 'setup',
  66. srcData: srcData,
  67. };
  68. return _POOL.Broadcast(setupMsg);
  69. },
  70. draw: function(type, genotype, width, height) {
  71. const p = _POOL.Enqueue({
  72. action: 'draw',
  73. type: type,
  74. genotype: genotype,
  75. width: width,
  76. height: height
  77. });
  78. return p;
  79. },
  80. calculateFitnesses: function(type, genotypes) {
  81. // Wait for them all to be done
  82. const workItems = genotypes.map((g, i) => ({genotype: g, index: i}));
  83. const chunkSize = genotypes.length / _POOL.length;
  84. const promises = [];
  85. while (workItems.length > 0) {
  86. const workSet = workItems.splice(0, chunkSize);
  87. const workItem = {
  88. action: 'work',
  89. work: workSet,
  90. type: type,
  91. };
  92. promises.push(_POOL.Enqueue(workItem));
  93. }
  94. return promises;
  95. },
  96. };
  97. })();