abbr / deasync

Turns async function into sync via JavaScript wrapper of Node event loop
MIT License
971 stars 73 forks source link

document alternative solution like `worker_threads` or `child_process` #145

Open JounQin opened 3 years ago

JounQin commented 3 years ago

worker_threads is almost fast same as current solution but requires no node bindings or node-gyp, while child_process is extremely slower.

See benchmark at https://github.com/rx-ts/synckit/blob/main/benchmarks/benchmark.esm.txt

JounQin commented 3 years ago

synckit seems much faster on Ubuntu GitHub Actions

$ node benchmarks/benchmark
┌───────────┬────────────┬──────────────┬──────────────────┬──────────────┬─────────────────┬────────────┬─────────────────┐
│  (index)  │  synckit   │ syncThreads  │ perf syncThreads │   deasync    │  perf deasync   │   native   │   perf native   │
├───────────┼────────────┼──────────────┼──────────────────┼──────────────┼─────────────────┼────────────┼─────────────────┤
│ loadTime  │ '28.35ms'  │   '1.71ms'   │ '16.58x slower'  │   '1.89ms'   │ '15.00x slower' │  '0.42ms'  │ '67.50x slower' │
│  runTime  │ '359.66ms' │ '12124.80ms' │ '33.71x faster'  │ '19369.17ms' │ '53.85x faster' │ '192.06ms' │ '1.87x slower'  │
│ totalTime │ '388.01ms' │ '12126.51ms' │ '31.25x faster'  │ '19371.06ms' │ '49.92x faster' │ '192.48ms' │ '2.02x slower'  │
└───────────┴────────────┴──────────────┴──────────────────┴──────────────┴─────────────────┴────────────┴─────────────────┘

https://github.com/rx-ts/synckit/runs/3043553657

jardicc commented 2 years ago

@JounQin I am very interested in it but can your solution do the exact same thing with callbacks? Can it do e.g. proper sleep()? Also is synced code executed in the same scripting context?

JounQin commented 2 years ago

@jardicc I'm not sure what's meaning, the async function should return Promise, you can always change your callbacks to Promise style.

The transformed function is executed in worker_threads, you need pass params into it, so, not the same script context.

sleep() will work and block the main thread.

See https://github.com/rx-ts/synckit/blob/main/test/worker-esm.ts

jardicc commented 2 years ago

@JounQin Ok. Thanks. For me, this could have huge potential. But it requires careful research from my side. Do you think that would be this possible to use sync WebSocket communication? Don't judge me... I have very good reasons to do so and I am not running a webserver.

JounQin commented 2 years ago

If you can wrap it into a Promise, then it should just work.

I don't know if it is something you want like:

// worker.js
const ws = new WebSocket()

let _resolve
let _reject

let loadWs = new Promise((resolve, reject) => {
  _resolve = resolve
  _reject = reject
})

let value

ws.on('data', (data) => {
  value = data
  _resolve()
})

we.once('error', _reject)

runAsWorker(async () => {
  await loadWs
  return value
})
// runner.js
const syncFn = createSyncFn(require.resolve('./worker'))

syncFn() // will wait for first ws loaded value and always get latest value
jardicc commented 2 years ago

@JounQin Ok, that is interesting... thanks for the inspiration to experiment with. In your example is client-side I think. Meanwhile, right now I do have "server" side in NodeJS. But since I have 1:1 connection maybe I could reverse it... but I would prefer not to do so since it requires more time to implement. :-D