developit / greenlet

🦎 Move an async function into its own thread.
https://npm.im/greenlet
4.67k stars 100 forks source link

Support for terminating workers? #33

Closed JamesLMilner closed 4 years ago

JamesLMilner commented 6 years ago

At the moment it doesn't appear greenlet supports terminating threads. From my experimentation it appears that even if workers are not referenced they do not seem to be destroyed:

spectacle b18024

After about 20 threads the client will become unresponsive / crash.

Being able to do something like:

import greenlet from 'greenlet'

let getName = greenlet( async username => {
    let url = `https://api.github.com/users/${username}`
    let res = await fetch(url)
    let profile = await res.json()
    return profile.name
})

console.log(await getName('developit'))
getName.terminate(); // Not sure if that's actually possible with the current setup

Would potentially help with the Web Worker lifecycle management.

developit commented 6 years ago

Hmm - the idea is that you should never be reexecuting greenlet() more than once per function. Creating threads in a loop is going to be bad for performance whether they get cleaned up or not.

FWIW it should be possible to create self-destruction workers using close():

const foo = greenlet(async () => {
  setTimeout(() => close());

  return 'hello'
});
pixelbucket-dev commented 5 years ago

Where does close() come from?

Wouldn't it be good to expose a terminate function from greenlet?

So WRT to the Readme example something like:

import greenlet from 'greenlet'

let {postMessage: getName, terminate} = greenlet( async username => {
    let url = `https://api.github.com/users/${username}`
    let res = await fetch(url)
    let profile = await res.json()
    return profile.name
})

console.log(await getName('developit'))
terminate();
pixelbucket-dev commented 5 years ago

What I found is to only instantiate greenlet on the module level, never inside a class/component. This avoids re-instantiation and therefore memory leaks. This should probably be documented because it is very important.

developit commented 4 years ago

@Nudelsieb yes, that's exactly right. I've added a section in the readme that clarifies this. Dynamic instantiation of workers for a task is rarely a good idea.

dwaltrip commented 2 years ago

First, thanks for developing and sharing this library! It looks great, and seems to make things much more ergonomic for many common use cases.

I have an expensive computation I'm doing: runExpensiveCalc(userInput). If the user changes the inputs while it is computing, then the old computation is no longer valid, and I need to re-run it with the new inputs.

This is my first time using Web Workers, but using vanilla workers, it looks like I can do this by calling terminate on the first worker and then start a second worker that receives the new user inputs. Without terminate, the first worker would needlessly continue working on its computation, which is now irrelevant.

Is there another way of doing this without terminate? Or is greenlet not intended for long-running computations that may need to be stopped?