lime icon indicating copy to clipboard operation
lime copied to clipboard

Add virtual threads and web workers.

Open player-03 opened this issue 4 years ago • 5 comments

This pull request adds virtual threads (thread-like code that runs entirely on the main thread), adds web workers (HTML5 threads), merges BackgroundWorker into ThreadPool, and helps programmers reduce their risk of race conditions, all while maintaining backwards compatibility. I've written a detailed tutorial to go with the new code, including embedded HTML5 examples.

This request supersedes #1503, resolves #1081, and resolves #1502.

player-03 avatar Feb 01 '22 00:02 player-03

Edit: my conclusions here turned out to be incorrect. See below for an update.

It would be nice to support web workers (as proposed in #1081), but it proved impossible to add them without breaking backwards compatibility. I tried making them opt-in, but even then they required the user to jump through so many hurdles that I concluded it wasn't worth it. Hurdles were just piling up.

  • If you want to pass a function (like FutureWork does), you need to convert it to ThreadFunction first. It's possible to do this incorrectly, making the function unusable, resulting in a 400+ character error with instructions to fix it. (And that's the short version!)
  • If you want to be able to access a class, you have to add it to the worker's header. I made a convenient function to copy the whole thing, so at least that wasn't hard. Then you'd have to add its parent classes, and any classes these classes referenced, and repeat.
  • When you pass a message, by default it makes a copy. If you're passing a large object and don't want to go through the slow process of copying it, you need to pass it as part of a second argument to sendComplete(). (But it also has to be in the first argument. It's a bit confusing.)
  • If you pass a class instance to or from a web worker, it will lose all its instance methods. You can fix this by calling restoreInstanceMethods()... but only partially. It will only restore the instance methods known at compile time. For instance, if you pass a Sprite but the compiler only knows it's a DisplayObject, it will become a DisplayObject, without any of the overridden methods.

It was at about that point I gave up on adding web workers to Lime. They just don't belong here. They belong in a separate library that can properly document them. (And I do plan to make that library.)

player-03 avatar Feb 01 '22 01:02 player-03

Correction: web workers are in fact viable! Thanks to Jonas Nyström and the others who wrote this article for the suggestion to reuse the existing script file.

I chose to sacrifice performance in places to provide a seamless user experience, but it works relatively well considering the number of restrictions imposed by web workers.

The fact that users are forced to use static functions actually makes it easier on them, as they don't have to deal with the confusion around instance functions. (That's assuming they opt in to use web workers. If not, they can use whatever functions they like.)

~~I've also encountered a strange issue with transferable objects.~~ Edit: fixed!

player-03 avatar Mar 01 '22 00:03 player-03

Finally. After... how long has it been now?

Finally, after four months (!!) of work, I have uncovered the truth about BackgroundWorker and ThreadPool.

The truth is, the differences between these classes are entirely artificial. I tried for so long to enforce those differences, to give each one its own use case, but in the end I failed.

I tried to restrict BackgroundWorker to a single thread. However, I needed to account for the possibility that the user would call run() multiple times, something the old version overlooked. Throwing an error seemed inappropriate, as did exiting silently, so the only viable option was to cancel the old thread and start a new one. And guess what? That meant BackgroundWorker was using more than one thread. Perhaps they weren't so different after all.

The two classes became more and more similar over the ensuing months, until only a single meaningful difference remained. That difference was that ThreadPool went out of its way to force you to use the same function for every job. There was no performance benefit to enforcing this restriction, nor did it make the code simpler. All it did was preserve a distinction between classes.

And this brings us to the present moment:

The truth about BackgroundWorker

(Before anyone asks, yes, they're both still backwards-compatible.)

player-03 avatar Mar 29 '22 18:03 player-03

Any updates on this?

ShaharMS avatar Sep 21 '22 21:09 ShaharMS

I think this should go in 8.1.0, but since there will be a couple more releases before then, we just have to wait.

Though @Dimensionscape mentioned at one point that he wanted to make different branches for different upcoming releases. Perhaps we could make a v8.1.0 branch and merge into that?

player-03 avatar Sep 22 '22 13:09 player-03