* Resolve `refs` across the pool. Chunks preserve input order; the returned * arrays are the in-order concatenation of the chunk results.
(refs: UnresolvedReference[])
| 236 | * arrays are the in-order concatenation of the chunk results. |
| 237 | */ |
| 238 | async resolveBatch(refs: UnresolvedReference[]): Promise<ChunkResult> { |
| 239 | if (this.failed) throw this.failed; |
| 240 | const chunkPromises: Promise<ChunkResult>[] = []; |
| 241 | for (let i = 0; i < refs.length; i += CHUNK_SIZE) { |
| 242 | const chunk = refs.slice(i, i + CHUNK_SIZE); |
| 243 | const id = this.nextId++; |
| 244 | // Least-busy dispatch keeps workers evenly loaded regardless of chunk |
| 245 | // cost variance; result order is fixed by the promise array, not by |
| 246 | // completion order. |
| 247 | const pw = this.workers.reduce((a, b) => (b.busy < a.busy ? b : a)); |
| 248 | pw.busy++; |
| 249 | chunkPromises.push( |
| 250 | new Promise<ChunkResult>((resolve, reject) => { |
| 251 | this.waiters.set(id, { resolve, reject }); |
| 252 | pw.worker.postMessage({ type: 'resolve', id, refs: chunk }); |
| 253 | }) |
| 254 | ); |
| 255 | } |
| 256 | const chunks = await Promise.all(chunkPromises); |
| 257 | const out: ChunkResult = { resolved: [], unresolved: [], deferredChain: [], deferredThisMember: [], byMethod: {} }; |
| 258 | for (const c of chunks) { |
| 259 | out.resolved.push(...c.resolved); |
| 260 | out.unresolved.push(...c.unresolved); |
| 261 | out.deferredChain.push(...c.deferredChain); |
| 262 | out.deferredThisMember.push(...c.deferredThisMember); |
| 263 | for (const [k, v] of Object.entries(c.byMethod)) out.byMethod[k] = (out.byMethod[k] || 0) + v; |
| 264 | } |
| 265 | return out; |
| 266 | } |
| 267 | |
| 268 | /** |
| 269 | * Run one synthesis pass (by SYNTH_PASSES name) on the least-busy worker. |
no test coverage detected