Skip to content

Commit 2541a1e

Browse files
onigoetzJounQin
andauthoredJan 3, 2024
feat!: use a single SharedArrayBuffer, remove useless bufferSize option (#154)
Co-authored-by: JounQin <admin@1stg.me>
1 parent e21f030 commit 2541a1e

File tree

6 files changed

+42
-51
lines changed

6 files changed

+42
-51
lines changed
 

‎.changeset/ten-sheep-applaud.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"synckit": minor
3+
---
4+
5+
feat!: use a single SharedArrayBuffer, remove useless `bufferSize` option

‎README.md

+9-11
Original file line numberDiff line numberDiff line change
@@ -111,20 +111,18 @@ export interface GlobalShim {
111111

112112
### Options
113113

114-
1. `bufferSize` same as env `SYNCKIT_BUFFER_SIZE`
115-
2. `timeout` same as env `SYNCKIT_TIMEOUT`
116-
3. `execArgv` same as env `SYNCKIT_EXEC_ARGV`
117-
4. `tsRunner` same as env `SYNCKIT_TS_RUNNER`
118-
5. `transferList`: Please refer Node.js [`worker_threads`](https://nodejs.org/api/worker_threads.html#:~:text=Default%3A%20true.-,transferList,-%3CObject%5B%5D%3E%20If) documentation
119-
6. `globalShims`: Similar like env `SYNCKIT_GLOBAL_SHIMS` but much more flexible which can be a `GlobalShim` `Array`, see `GlobalShim`'s [definition](#types) for more details
114+
1. `timeout` same as env `SYNCKIT_TIMEOUT`
115+
2. `execArgv` same as env `SYNCKIT_EXEC_ARGV`
116+
3. `tsRunner` same as env `SYNCKIT_TS_RUNNER`
117+
4. `transferList`: Please refer Node.js [`worker_threads`](https://nodejs.org/api/worker_threads.html#:~:text=Default%3A%20true.-,transferList,-%3CObject%5B%5D%3E%20If) documentation
118+
5. `globalShims`: Similar like env `SYNCKIT_GLOBAL_SHIMS` but much more flexible which can be a `GlobalShim` `Array`, see `GlobalShim`'s [definition](#types) for more details
120119

121120
### Envs
122121

123-
1. `SYNCKIT_BUFFER_SIZE`: `bufferSize` to create `SharedArrayBuffer` for `worker_threads` (default as `1024`)
124-
2. `SYNCKIT_TIMEOUT`: `timeout` for performing the async job (no default)
125-
3. `SYNCKIT_EXEC_ARGV`: List of node CLI options passed to the worker, split with comma `,`. (default as `[]`), see also [`node` docs](https://nodejs.org/api/worker_threads.html)
126-
4. `SYNCKIT_TS_RUNNER`: Which TypeScript runner to be used, it could be very useful for development, could be `'ts-node' | 'esbuild-register' | 'esbuild-runner' | 'swc' | 'tsx'`, `'ts-node'` is used by default, make sure you have installed them already
127-
5. `SYNCKIT_GLOBAL_SHIMS`: Whether to enable the default `DEFAULT_GLOBAL_SHIMS_PRESET` as `globalShims`
122+
1. `SYNCKIT_TIMEOUT`: `timeout` for performing the async job (no default)
123+
2. `SYNCKIT_EXEC_ARGV`: List of node CLI options passed to the worker, split with comma `,`. (default as `[]`), see also [`node` docs](https://nodejs.org/api/worker_threads.html)
124+
3. `SYNCKIT_TS_RUNNER`: Which TypeScript runner to be used, it could be very useful for development, could be `'ts-node' | 'esbuild-register' | 'esbuild-runner' | 'swc' | 'tsx'`, `'ts-node'` is used by default, make sure you have installed them already
125+
4. `SYNCKIT_GLOBAL_SHIMS`: Whether to enable the default `DEFAULT_GLOBAL_SHIMS_PRESET` as `globalShims`
128126

129127
### TypeScript
130128

‎src/index.ts

+26-36
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import type {
2626
WorkerToMainMessage,
2727
} from './types.js'
2828

29+
const INT32_BYTES = 4
30+
2931
export * from './types.js'
3032

3133
export const TsRunner = {
@@ -44,22 +46,15 @@ export const TsRunner = {
4446
export type TsRunner = ValueOf<typeof TsRunner>
4547

4648
const {
47-
SYNCKIT_BUFFER_SIZE,
4849
SYNCKIT_TIMEOUT,
4950
SYNCKIT_EXEC_ARGV,
5051
SYNCKIT_TS_RUNNER,
5152
SYNCKIT_GLOBAL_SHIMS,
5253
NODE_OPTIONS,
5354
} = process.env
5455

55-
export const DEFAULT_BUFFER_SIZE = SYNCKIT_BUFFER_SIZE
56-
? +SYNCKIT_BUFFER_SIZE
57-
: undefined
58-
5956
export const DEFAULT_TIMEOUT = SYNCKIT_TIMEOUT ? +SYNCKIT_TIMEOUT : undefined
6057

61-
export const DEFAULT_WORKER_BUFFER_SIZE = DEFAULT_BUFFER_SIZE || 1024
62-
6358
/* istanbul ignore next */
6459
export const DEFAULT_EXEC_ARGV = SYNCKIT_EXEC_ARGV?.split(',') || []
6560

@@ -86,7 +81,6 @@ export const MTS_SUPPORTED_NODE_VERSION = 16
8681
const syncFnCache = new Map<string, AnyFn>()
8782

8883
export interface SynckitOptions {
89-
bufferSize?: number
9084
timeout?: number
9185
execArgv?: string[]
9286
tsRunner?: TsRunner
@@ -109,40 +103,30 @@ export function extractProperties<T>(object?: T) {
109103
}
110104
}
111105

112-
export function createSyncFn<T extends AnyAsyncFn>(
113-
workerPath: string,
114-
bufferSize?: number,
115-
timeout?: number,
116-
): Syncify<T>
117-
export function createSyncFn<T extends AnyAsyncFn>(
118-
workerPath: string,
119-
options?: SynckitOptions,
120-
): Syncify<T>
121-
export function createSyncFn<R, T extends AnyAsyncFn<R>>(
106+
export function createSyncFn<T extends AnyAsyncFn<R>, R = unknown>(
122107
workerPath: string,
123-
bufferSizeOrOptions?: SynckitOptions | number,
124-
timeout?: number,
125-
) {
108+
timeoutOrOptions?: SynckitOptions | number,
109+
): Syncify<T> {
126110
if (!path.isAbsolute(workerPath)) {
127111
throw new Error('`workerPath` must be absolute')
128112
}
129113

130114
const cachedSyncFn = syncFnCache.get(workerPath)
131115

132116
if (cachedSyncFn) {
133-
return cachedSyncFn
117+
return cachedSyncFn as Syncify<T>
134118
}
135119

136120
const syncFn = startWorkerThread<R, T>(
137121
workerPath,
138-
/* istanbul ignore next */ typeof bufferSizeOrOptions === 'number'
139-
? { bufferSize: bufferSizeOrOptions, timeout }
140-
: bufferSizeOrOptions,
122+
/* istanbul ignore next */ typeof timeoutOrOptions === 'number'
123+
? { timeout: timeoutOrOptions }
124+
: timeoutOrOptions,
141125
)
142126

143127
syncFnCache.set(workerPath, syncFn)
144128

145-
return syncFn
129+
return syncFn as Syncify<T>
146130
}
147131

148132
const cjsRequire =
@@ -379,6 +363,9 @@ const _dirname =
379363
? path.dirname(fileURLToPath(import.meta.url))
380364
: /* istanbul ignore next */ __dirname
381365

366+
let sharedBuffer: SharedArrayBuffer | undefined
367+
let sharedBufferView: Int32Array | undefined
368+
382369
export const generateGlobals = (
383370
workerPath: string,
384371
globalShims: GlobalShim[],
@@ -421,7 +408,6 @@ export const generateGlobals = (
421408
function startWorkerThread<R, T extends AnyAsyncFn<R>>(
422409
workerPath: string,
423410
{
424-
bufferSize = DEFAULT_WORKER_BUFFER_SIZE,
425411
timeout = DEFAULT_TIMEOUT,
426412
execArgv = DEFAULT_EXEC_ARGV,
427413
tsRunner = DEFAULT_TS_RUNNER,
@@ -480,6 +466,11 @@ function startWorkerThread<R, T extends AnyAsyncFn<R>>(
480466
: []
481467
).filter(({ moduleName }) => isPkgAvailable(moduleName))
482468

469+
// We store a single Byte in the SharedArrayBuffer
470+
// for the notification, we can used a fixed size
471+
sharedBuffer ??= new SharedArrayBuffer(INT32_BYTES)
472+
sharedBufferView ??= new Int32Array(sharedBuffer, 0, 1)
473+
483474
const useGlobals = finalGlobalShims.length > 0
484475

485476
const useEval = isTs ? !tsUseEsm : !jsUseEsm && useGlobals
@@ -501,7 +492,7 @@ function startWorkerThread<R, T extends AnyAsyncFn<R>>(
501492
: workerPathUrl,
502493
{
503494
eval: useEval,
504-
workerData: { workerPort },
495+
workerData: { sharedBuffer, workerPort },
505496
transferList: [workerPort, ...transferList],
506497
execArgv: finalExecArgv,
507498
},
@@ -512,13 +503,12 @@ function startWorkerThread<R, T extends AnyAsyncFn<R>>(
512503
const syncFn = (...args: Parameters<T>): R => {
513504
const id = nextID++
514505

515-
const sharedBuffer = new SharedArrayBuffer(bufferSize)
516-
const sharedBufferView = new Int32Array(sharedBuffer)
517-
518-
const msg: MainToWorkerMessage<Parameters<T>> = { sharedBuffer, id, args }
506+
const msg: MainToWorkerMessage<Parameters<T>> = { id, args }
519507
worker.postMessage(msg)
520508

521-
const status = Atomics.wait(sharedBufferView, 0, 0, timeout)
509+
const status = Atomics.wait(sharedBufferView!, 0, 0, timeout)
510+
// Reset SharedArrayBuffer for next call
511+
Atomics.store(sharedBufferView!, 0, 0)
522512

523513
/* istanbul ignore if */
524514
if (!['ok', 'not-equal'].includes(status)) {
@@ -560,14 +550,14 @@ export function runAsWorker<
560550
return
561551
}
562552

563-
const { workerPort } = workerData as WorkerData
553+
const { workerPort, sharedBuffer } = workerData as WorkerData
554+
const sharedBufferView = new Int32Array(sharedBuffer, 0, 1)
564555

565556
parentPort!.on(
566557
'message',
567-
({ sharedBuffer, id, args }: MainToWorkerMessage<Parameters<T>>) => {
558+
({ id, args }: MainToWorkerMessage<Parameters<T>>) => {
568559
// eslint-disable-next-line @typescript-eslint/no-floating-promises
569560
;(async () => {
570-
const sharedBufferView = new Int32Array(sharedBuffer)
571561
let msg: WorkerToMainMessage<R>
572562
try {
573563
msg = { id, result: await fn(...args) }

‎src/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ export type PromiseType<T extends AnyPromise> = T extends Promise<infer R>
2222
export type ValueOf<T> = T[keyof T]
2323

2424
export interface MainToWorkerMessage<T extends unknown[]> {
25-
sharedBuffer: SharedArrayBuffer
2625
id: number
2726
args: T
2827
}
2928

3029
export interface WorkerData {
30+
sharedBuffer: SharedArrayBuffer
3131
workerPort: MessagePort
3232
}
3333

‎test/fn.spec.ts

-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ const { SYNCKIT_TIMEOUT } = process.env
1313
beforeEach(() => {
1414
jest.resetModules()
1515

16-
delete process.env.SYNCKIT_BUFFER_SIZE
1716
delete process.env.SYNCKIT_GLOBAL_SHIMS
1817

1918
if (SYNCKIT_TIMEOUT) {
@@ -95,7 +94,6 @@ test('createSyncFn', () => {
9594
})
9695

9796
test('timeout', async () => {
98-
process.env.SYNCKIT_BUFFER_SIZE = '0'
9997
process.env.SYNCKIT_TIMEOUT = '1'
10098

10199
const { createSyncFn } = await import('synckit')

‎test/ts-runner.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ test('unknown ts runner', async () => {
134134
const { createSyncFn } = await import('synckit')
135135

136136
expect(() =>
137-
// @ts-expect-error
138137
createSyncFn<AsyncWorkerFn>(path.resolve(_dirname, 'worker.js'), {
138+
// @ts-expect-error
139139
tsRunner: 'unknown',
140140
}),
141141
).toThrowErrorMatchingInlineSnapshot(`"Unknown ts runner: unknown"`)

0 commit comments

Comments
 (0)
Please sign in to comment.