You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					204 lines
				
				4.0 KiB
			
		
		
			
		
	
	
					204 lines
				
				4.0 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Object.defineProperty(exports, '__esModule', {
							 | 
						||
| 
								 | 
							
								  value: true
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								exports.default = void 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var _types = require('./types');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _defineProperty(obj, key, value) {
							 | 
						||
| 
								 | 
							
								  if (key in obj) {
							 | 
						||
| 
								 | 
							
								    Object.defineProperty(obj, key, {
							 | 
						||
| 
								 | 
							
								      value: value,
							 | 
						||
| 
								 | 
							
								      enumerable: true,
							 | 
						||
| 
								 | 
							
								      configurable: true,
							 | 
						||
| 
								 | 
							
								      writable: true
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    obj[key] = value;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return obj;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Farm {
							 | 
						||
| 
								 | 
							
								  constructor(numOfWorkers, callback, computeWorkerKey) {
							 | 
						||
| 
								 | 
							
								    _defineProperty(this, '_computeWorkerKey', void 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _defineProperty(this, '_cacheKeys', void 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _defineProperty(this, '_callback', void 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _defineProperty(this, '_last', void 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _defineProperty(this, '_locks', void 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _defineProperty(this, '_numOfWorkers', void 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _defineProperty(this, '_offset', void 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _defineProperty(this, '_queue', void 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this._cacheKeys = Object.create(null);
							 | 
						||
| 
								 | 
							
								    this._callback = callback;
							 | 
						||
| 
								 | 
							
								    this._last = [];
							 | 
						||
| 
								 | 
							
								    this._locks = [];
							 | 
						||
| 
								 | 
							
								    this._numOfWorkers = numOfWorkers;
							 | 
						||
| 
								 | 
							
								    this._offset = 0;
							 | 
						||
| 
								 | 
							
								    this._queue = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (computeWorkerKey) {
							 | 
						||
| 
								 | 
							
								      this._computeWorkerKey = computeWorkerKey;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  doWork(method, ...args) {
							 | 
						||
| 
								 | 
							
								    const customMessageListeners = new Set();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const addCustomMessageListener = listener => {
							 | 
						||
| 
								 | 
							
								      customMessageListeners.add(listener);
							 | 
						||
| 
								 | 
							
								      return () => {
							 | 
						||
| 
								 | 
							
								        customMessageListeners.delete(listener);
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const onCustomMessage = message => {
							 | 
						||
| 
								 | 
							
								      customMessageListeners.forEach(listener => listener(message));
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const promise = new Promise((resolve, reject) => {
							 | 
						||
| 
								 | 
							
								      const computeWorkerKey = this._computeWorkerKey;
							 | 
						||
| 
								 | 
							
								      const request = [_types.CHILD_MESSAGE_CALL, false, method, args];
							 | 
						||
| 
								 | 
							
								      let worker = null;
							 | 
						||
| 
								 | 
							
								      let hash = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (computeWorkerKey) {
							 | 
						||
| 
								 | 
							
								        hash = computeWorkerKey.call(this, method, ...args);
							 | 
						||
| 
								 | 
							
								        worker = hash == null ? null : this._cacheKeys[hash];
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const onStart = worker => {
							 | 
						||
| 
								 | 
							
								        if (hash != null) {
							 | 
						||
| 
								 | 
							
								          this._cacheKeys[hash] = worker;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const onEnd = (error, result) => {
							 | 
						||
| 
								 | 
							
								        customMessageListeners.clear();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (error) {
							 | 
						||
| 
								 | 
							
								          reject(error);
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          resolve(result);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const task = {
							 | 
						||
| 
								 | 
							
								        onCustomMessage,
							 | 
						||
| 
								 | 
							
								        onEnd,
							 | 
						||
| 
								 | 
							
								        onStart,
							 | 
						||
| 
								 | 
							
								        request
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (worker) {
							 | 
						||
| 
								 | 
							
								        this._enqueue(task, worker.getWorkerId());
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        this._push(task);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    promise.UNSTABLE_onCustomMessage = addCustomMessageListener;
							 | 
						||
| 
								 | 
							
								    return promise;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _getNextTask(workerId) {
							 | 
						||
| 
								 | 
							
								    let queueHead = this._queue[workerId];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    while (queueHead && queueHead.task.request[1]) {
							 | 
						||
| 
								 | 
							
								      queueHead = queueHead.next || null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this._queue[workerId] = queueHead;
							 | 
						||
| 
								 | 
							
								    return queueHead && queueHead.task;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _process(workerId) {
							 | 
						||
| 
								 | 
							
								    if (this._isLocked(workerId)) {
							 | 
						||
| 
								 | 
							
								      return this;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const task = this._getNextTask(workerId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!task) {
							 | 
						||
| 
								 | 
							
								      return this;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const onEnd = (error, result) => {
							 | 
						||
| 
								 | 
							
								      task.onEnd(error, result);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      this._unlock(workerId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      this._process(workerId);
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    task.request[1] = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this._lock(workerId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this._callback(
							 | 
						||
| 
								 | 
							
								      workerId,
							 | 
						||
| 
								 | 
							
								      task.request,
							 | 
						||
| 
								 | 
							
								      task.onStart,
							 | 
						||
| 
								 | 
							
								      onEnd,
							 | 
						||
| 
								 | 
							
								      task.onCustomMessage
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _enqueue(task, workerId) {
							 | 
						||
| 
								 | 
							
								    const item = {
							 | 
						||
| 
								 | 
							
								      next: null,
							 | 
						||
| 
								 | 
							
								      task
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (task.request[1]) {
							 | 
						||
| 
								 | 
							
								      return this;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (this._queue[workerId]) {
							 | 
						||
| 
								 | 
							
								      this._last[workerId].next = item;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      this._queue[workerId] = item;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this._last[workerId] = item;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this._process(workerId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return this;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _push(task) {
							 | 
						||
| 
								 | 
							
								    for (let i = 0; i < this._numOfWorkers; i++) {
							 | 
						||
| 
								 | 
							
								      this._enqueue(task, (this._offset + i) % this._numOfWorkers);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    this._offset++;
							 | 
						||
| 
								 | 
							
								    return this;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _lock(workerId) {
							 | 
						||
| 
								 | 
							
								    this._locks[workerId] = true;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _unlock(workerId) {
							 | 
						||
| 
								 | 
							
								    this._locks[workerId] = false;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _isLocked(workerId) {
							 | 
						||
| 
								 | 
							
								    return this._locks[workerId];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								exports.default = Farm;
							 |