fast-worker
Version:
Module for executing heavy tasks in parallel, by providing a `Promise` based interface, minimum overhead, and bound workers.
3 lines (2 loc) • 9.33 kB
JavaScript
Object.defineProperty(exports,"__esModule",{value:!0});var e=require("module"),t=require("path"),r=require("url"),n=require("os"),s=require("worker_threads");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function i(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var a=o(t);class FastWorkerProxy{get disposed(){throw new Error("Property not implemented.")}dispose(){throw new Error("Function not implemented.")}}const c=e=>{const t=Object.create(null);return new Proxy(t,{get:(t,r,n)=>"string"!=typeof r||r.startsWith("_")?Reflect.get(t,r,n):t[r]??(t[r]=(...t)=>e(r,t))})},l=e=>{let t,r=!1;return(...n)=>(r||(t=e(...n),r=!0),t)},u="string"==typeof __filename?__filename:r.fileURLToPath("undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("index.js",document.baseURI).href),h=u.endsWith(".mjs"),f=(t=>{if(t.endsWith(".mjs"))return e=>{return a.default.isAbsolute(e)&&(e=r.pathToFileURL(e).href),t=e,Promise.resolve().then((function(){return i(require(t))}));var t};{const r=e.createRequire(t);return async e=>r(e)}})(u),d="fast-worker",m=()=>{let e,t;const r=new Promise(((r,n)=>{e=r,t=n}));let n=!1;return r.fulfilled=!1,r.rejected=!1,r.resolve=t=>{n||(r.fulfilled=n=!0,e(t))},r.reject=e=>{n||(r.rejected=n=!0,t(e))},r.catch(),r},p=Symbol.for(`${d}:stringifyCallbackParameterTransfer`),y=Symbol.for(`${d}@2.1.0:callbackMap`),_=globalThis[y]??(globalThis[y]=new Map),g="string"==typeof __filename?__filename:r.fileURLToPath("undefined"==typeof document?new(require("url").URL)("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("index.js",document.baseURI).href),w=a.default.join(a.default.dirname(g),"worker-entry.mjs"),{getPrototypeOf:k,setPrototypeOf:v,prototype:x}=Object;class FastWorkerItemStatusError extends Error{}const b=process.argv.slice(2),W=[...process.execArgv];W.some((e=>e.startsWith("--experimental-specifier-resolution")))||W.push("--experimental-specifier-resolution=node"),W.includes("--experimental-import-meta-resolve")||W.unshift("--experimental-import-meta-resolve"),W.includes("--experimental-modules")||W.unshift("--experimental-modules");class FastWorkerItem extends s.Worker{constructor(e){super(w,{env:e?{...process.env,...e}:void 0,argv:b,execArgv:W}),this._runnings=0,this._closed=!1,this._callStates=new Map,this._exitPromise=m(),this._k=0,this._ready=m(),this._terminate=l(super.terminate.bind(this)),this._ready.catch((()=>this.terminate()));let t=setTimeout((()=>{t=void 0,this._ready.reject(new FastWorkerItemStatusError("Worker-thread load timeout."))}),32767);this.on("exit",(()=>{this._closed=!0,this._ready.reject(new FastWorkerItemStatusError("Worker-thread is exited.")),this._exitPromise.resolve()})),this.on("message",(e=>{switch(e[0]){case 2:{const[t,r,n,s]=e,o=_.get(n);o?async function(e,t,r,n){try{const s=await t(...n);e.postMessage([3,r,s])}catch(t){e.postMessage([65539,r,closed])}}(this,o,r,s).catch():this.postMessage([65539,r,new Error(`Callback id '${n} is notfound.\nIn the worker thread, the lifetime of the 'callback' function is limited to the execution of the function, and you may have called the 'callback' function outside of the execution of the function'`)])}break;case 1:{const[t,r,n]=e;this._callStates.get(r)?.resolve(n)}break;case 65537:{const[t,r,n]=e;if(n&&"object"==typeof n)switch(k(n)){case null:case x:v(n,Error.prototype)}this._callStates.get(r)?.reject(n)}break;case 256:this._closed=!0,this._ready.reject(new FastWorkerItemStatusError("Worker-thread is exited.")),this._exitPromise.resolve();break;case 768:clearTimeout(t),this._ready.resolve()}})),this._exitPromise.finally((()=>{for(const e of this._callStates.values())e.reject(new FastWorkerItemStatusError("Worker-thread is exited."));this._callStates.clear()}))}get ready(){return this._ready.fulfilled}get closed(){return this._closed}get runnings(){return this._runnings}whenReady(){return this._ready}whenClosed(){return this._exitPromise}invokeMethod(e,t,r,n,s){return this._invoke(1,[e,t,r,n],s,(()=>new Error(`Invoke method '${t}' in module '${e}' timeout.`)))}async terminate(){return this.postMessage([256]),await this._exitPromise,this._terminate()}async _invoke(e,t,r,n){if(this._closed)throw new FastWorkerItemStatusError("Worker-thread is exited.");if(!this.ready&&(await this.whenReady(),this._closed))throw new FastWorkerItemStatusError("Worker-thread is exited.");const s=++this._k,o=m();this._callStates.set(s,o);let i=null!==r&&r>=0?setTimeout((()=>{i=void 0,o.reject(n())}),r):void 0;++this._runnings,this.postMessage([e,s,...t]);try{return await o}finally{--this._runnings,void 0!==i&&clearTimeout(i),this._callStates.delete(s)}}}const j=e=>new Promise((t=>{setTimeout(t,e)})),M=async(e,t,r)=>{const n=(await f(e))?.[t];if("function"!=typeof n)throw new Error(`Method '${t}' in module '${e}' is not a function.`);return n(...r)},R=Symbol.for(`${d}@2.1.0`),P=()=>{let e=globalThis[R];if(e&&e[R]===R)return e;const t=Math.max(2,n.cpus().length-1),r=Math.max(1,Math.trunc(t/1.75)),s=[],o=[];let i=0,a=0;const c=(e=s.length)=>{let t=!1;const n=new FastWorkerItem({FAST_WORKER_LOWER_LEVEL:e>=r?"true":""}),i=()=>{if(t)return;t=!0;const e=s.indexOf(n);e>=0&&s.splice(e,1)};if(n.whenClosed().finally(i),n.whenReady().catch(i),o.length>0){const e=m.bind(n);for(const t of o)t(e,!1)}return n},l=()=>{if(s.length>=t)return;const e=c();return s.push(e),e},u=e=>{const t=[],r=[];for(let n=0,s=e.length;n<s;++n){const s=e[n];if("function"==typeof s)if(s[p])r[n]=s.toString();else{const e=r[n]=++a;_.set(e,s)}else t[n]=s}return[t,r]},d=e=>{for(const t of e)if("number"==typeof t){_.get(t)&&_.delete(t)}},m=async function(e,t,r,n=5e3,s=0,o){const[i,a]=u(r);let c,l=Math.max(0,Math.trunc(s))+1;for(let r=0;r<l;)try{return await this.invokeMethod(e,t,i,a,n)}catch(e){c=e,++r<l&&await j(o)}throw a&&d(a),c},y=(e,t,r,n,o,a)=>{let u=(()=>{let e,t=1/0;for(let r=0;r<s.length;++r){let n=s[r];if(n.closed&&(n=s[r]=c(r)),!n.ready)continue;const{runnings:o}=n;if(0===o){t=0,e=n;break}o<t&&(t=o,e=n)}if(e&&e.runnings>=i+2&&(e=l()??e),!e){const t=s.filter((e=>!e.closed));e=t[Math.trunc(Math.random()*t.length)]??s[0]}return e})();if(!o&&(u.closed||!u.ready||u.runnings>=i+2))return++i,f(e).then((n=>{const s=n?.[t];if("function"!=typeof s)throw new Error(`Method '${t}' in module '${e}' is not a function.`);return s(...r)})).finally((()=>{--i}));const[h,d]=a();return u.invokeMethod(e,t,h,d,n)};let g,w=0;return globalThis[R]={invokeMethod:async(e,t,r,n=5e3,s=0,o,i=(h?void 0:e.endsWith(".mjs")))=>{let a,c,l,f=Math.max(0,Math.trunc(s))+1;const m=()=>{if(l)return[c,l];const e=u(r);return[c,l]=e,e};for(let s=0;s<f;)try{return await y(e,t,r,n,i,m)}catch(e){a=e,e instanceof FastWorkerItemStatusError&&++f,++s<f&&await j(o)}throw l&&d(l),a},onInit:(e,t=!1)=>{for(const t of s)e(m.bind(t),!1);o.push(e),t||e(M,!0)},offInit:e=>{const t=o.indexOf(e);t>=0&&o.splice(t,1)},every:(e,t=!1)=>{for(const t of s)t.closed||e(m.bind(t),!1);t||e(M,!0)},ref:()=>{if(++w,clearTimeout(g),s.length<r)for(let e=0;e<r;++e)l()},unref:()=>{--w,clearTimeout(g),0===w&&(g=setTimeout((()=>{if(g=void 0,0===w){for(const e of s)e.terminate();s.splice(0,s.length)}}),g?1e3:100))},[R]:R}},S=(e,t,r,n)=>l((()=>{t&&e.offInit(t),r&&e.every(r,n),e.unref()})),E="undefined"!=typeof FinalizationRegistry?(()=>{const e=new FinalizationRegistry((e=>{e()}));return(t,r,n,s,o)=>{const i=S(r,n,s,o);return e.register(t,i),i}})():(e,t,r,n,s)=>S(t,r,n,s);class FastWorkerRaw{constructor(e,t){const r=P();this.methods=Object.create(null),this._p=r,this._m=e,this.options=t??(t=Object.create(null)),r.ref();const n=t?.onInit,s=t?.onCleanup;let o,i;"function"==typeof n&&(o=(e,r)=>{const s=c(((r,n)=>e(this._m,r,n,t.timeout,t.maxRetries||0,t.retryInterval)));n.call(s,s,r)},r.onInit(o,t.onlyExecInWorker)),"function"==typeof s&&(i=(e,r)=>{const n=c(((r,n)=>e(this._m,r,n,t.timeout,t.maxRetries||0,t.retryInterval)));s.call(n,n,r)});const a=E(this,r,o,i,t?.onlyExecInWorker);this.dispose=()=>{a(),this._p=void 0}}invokeMethod(e,t){if(!this._p)throw new Error("This instance of FastWorker is disposed.");const{options:r}=this;return this._p.invokeMethod(this._m,e,t,r.timeout,r.maxRetries||0,r.retryInterval,r.onlyExecInWorker)}getMethod(e){return this.methods[e]??(this.methods[e]=(...t)=>this.invokeMethod(e,t))}get disposed(){return!this._p}}exports.asyncCallbackParameterTransfer=e=>async(...t)=>e(...t),exports.createFastWorker=(e,t)=>{const r=new FastWorkerRaw(e,t);return n=r,new Proxy(new FastWorkerProxy,{get:(e,t,r)=>{switch(t){case"dispose":return n.dispose;case"disposed":return n.disposed}return"string"!=typeof t||t.startsWith("_")?Reflect.get(e,t,r):n.getMethod(t)},has:(e,t)=>t in n.methods||Reflect.has(e,t),ownKeys:e=>{const t=Array.from(Reflect.ownKeys(e));return t.push(...Object.keys(n.methods)),t}});var n},exports.stringifyCallbackParameterTransfer=e=>{const t=e.bind(void 0),r=e.toString();return Object.defineProperty(t,"toString",{configurable:!0,value:()=>r}),Object.defineProperty(t,p,{value:!0}),t};
//# sourceMappingURL=index.js.map
;