forked from sheetjs/docs.sheetjs.com
		
	
		
			
				
	
	
		
			89 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // This example from https://nodejs.org/dist/latest/docs/api/worker_threads.html
 | |
| // Documentation code redistributed under the MIT license.
 | |
| // Copyright Node.js contributors
 | |
| 
 | |
| import { AsyncResource } from 'node:async_hooks';
 | |
| import { EventEmitter } from 'node:events';
 | |
| import { Worker } from 'node:worker_threads';
 | |
| 
 | |
| const kTaskInfo = Symbol('kTaskInfo');
 | |
| const kWorkerFreedEvent = Symbol('kWorkerFreedEvent');
 | |
| 
 | |
| class WorkerPoolTaskInfo extends AsyncResource {
 | |
|   constructor(callback) {
 | |
|     super('WorkerPoolTaskInfo');
 | |
|     this.callback = callback;
 | |
|   }
 | |
| 
 | |
|   done(err, result) {
 | |
|     this.runInAsyncScope(this.callback, null, err, result);
 | |
|     this.emitDestroy();  // `TaskInfo`s are used only once.
 | |
|   }
 | |
| }
 | |
| 
 | |
| export default class WorkerPool extends EventEmitter {
 | |
|   constructor(numThreads) {
 | |
|     super();
 | |
|     this.numThreads = numThreads;
 | |
|     this.workers = [];
 | |
|     this.freeWorkers = [];
 | |
|     this.tasks = [];
 | |
| 
 | |
|     for (let i = 0; i < numThreads; i++)
 | |
|       this.addNewWorker();
 | |
| 
 | |
|     // Any time the kWorkerFreedEvent is emitted, dispatch
 | |
|     // the next task pending in the queue, if any.
 | |
|     this.on(kWorkerFreedEvent, () => {
 | |
|       if (this.tasks.length > 0) {
 | |
|         const { task, callback } = this.tasks.shift();
 | |
|         this.runTask(task, callback);
 | |
|       }
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   addNewWorker() {
 | |
|     const worker = new Worker(new URL('worker.js', import.meta.url));
 | |
|     worker.on('message', (result) => {
 | |
|       // In case of success: Call the callback that was passed to `runTask`,
 | |
|       // remove the `TaskInfo` associated with the Worker, and mark it as free
 | |
|       // again.
 | |
|       worker[kTaskInfo].done(null, result);
 | |
|       worker[kTaskInfo] = null;
 | |
|       this.freeWorkers.push(worker);
 | |
|       this.emit(kWorkerFreedEvent);
 | |
|     });
 | |
|     worker.on('error', (err) => {
 | |
|       // In case of an uncaught exception: Call the callback that was passed to
 | |
|       // `runTask` with the error.
 | |
|       if (worker[kTaskInfo])
 | |
|         worker[kTaskInfo].done(err, null);
 | |
|       else
 | |
|         this.emit('error', err);
 | |
|       // Remove the worker from the list and start a new Worker to replace the
 | |
|       // current one.
 | |
|       this.workers.splice(this.workers.indexOf(worker), 1);
 | |
|       this.addNewWorker();
 | |
|     });
 | |
|     this.workers.push(worker);
 | |
|     this.freeWorkers.push(worker);
 | |
|     this.emit(kWorkerFreedEvent);
 | |
|   }
 | |
| 
 | |
|   runTask(task, callback) {
 | |
|     if (this.freeWorkers.length === 0) {
 | |
|       // No free threads, wait until a worker thread becomes free.
 | |
|       this.tasks.push({ task, callback });
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     const worker = this.freeWorkers.pop();
 | |
|     worker[kTaskInfo] = new WorkerPoolTaskInfo(callback);
 | |
|     worker.postMessage(task);
 | |
|   }
 | |
| 
 | |
|   close() {
 | |
|     for (const worker of this.workers) worker.terminate();
 | |
|   }
 | |
| }
 |