-
-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Proposal]: Support for Workers #620
Comments
Will the Worker be able to leverage FTL JIT compilation ? If not, it loses a lot of value for me. It should be possible to leverage FTL JIT compilation if the worker is implemented via a WKWebView, rather than a JSContext. |
Hi @speigg. Worker threads will not take advantage of the FTL JIT but keep in mind that the same is valid for the main JS thread too. The lack of FTL JIT compilation is due to iOS restriction which forbids allocating writable and executable memory. Implementing Workers via
Can you be more specific on this? It would be great if you provide some use cases in which a lot of value is lost due to the lack of FTL JIT. |
I'm decrypting messages using openpgpjs. In the main JS thread, this can pause the UI for up to 8 seconds. I have it now working in a hacked together web worker with some basic structured cloning support (just serializing/deserializing typed arrays and Date objects, not dealing with cyclic references or any other web worker features) using a WkWebView. This cuts down the decryption time to about a second. A second I can deal with, but for my app 8 seconds is way too long, as the decryption happens in response to a user action and the user would be forced to wait while things "load" for 8 seconds or more. The other nice thing about WKWebView as a worker (for me) is that openpgp can automatically leverage the built in web crypto APIs. |
Perhaps the limitations you mention with the built-in JSC were unsuitable for the main JS Thread (in order to support performant access to native libraries, I'm guessing?), and these limitations may not be as much of a concern for web worker use cases. I think it would be a great balance to have the main thread be "slower" but with quick interop between native and JS, while a web worker runs JS in a highly optimized manner but with slow interop with native libraries. Or perhaps even allowing a developer to choose how the worker should run: optimizing for interop, or for raw JS performance. |
Hi @speigg Having a custom JSC build allow us to use the C++ API of JSC which brings many of the runtime features. Some of them are:
Other benefits of using a custom JSC build are:
Possibly, we can add more bullets to the list if we ever start working on alternative solution (e.g. To be honest, I like the idea of allowing a developer to choose how the worker should run but even if we are still fine to give up some of the runtime features in order to support On your particular case: |
Yes, a native library would work too (though I would have to create a plugin that wraps an appropriate library for each platform). |
This comment was marked as abuse.
This comment was marked as abuse.
How does one go about experimenting with the preview channel of the WebWorkers? |
If you want to try them out now, you'll have to checkout this branch and create an Xcode project as instructed in the readme. After that open the HelloWorld target and create some JS files in the |
@jasssonpet Sounds good. I'm gonna play around with this 😄 |
Is there any plan to move forward on this? I would love to be able to pass native object. |
Hi @farfromrefug, we haven't planned on new worker features for the immediate future. But we've managed to devise a workaround for passing native instances to workers by passing their pointers instead. Taking the unit test from the above pull request for example you can achieve it like this: var worker = new Worker("./EvalWorker.js");
var nativeDict = NSDictionary.dictionaryWithObjectForKey("value", "key");
var message = {
value: { dictionaryPtr: interop.handleof(nativeDict).toNumber() }
};
// increase reference count to account for `dictionaryPtr`
nativeDict.retain();
worker.postMessage(message); In the worker you can retrieve the native object like this: function pointerTo(type, value) {
var outerPtr = interop.alloc(interop.sizeof(interop.Pointer));
var outerRef = new interop.Reference(type, outerPtr);
outerRef.value = value;
return outerPtr;
}
function valueFromPointerNumber(type, value) {
const ptr = new interop.Pointer(value);
const ptrToPtr = pointerTo(interop.Pointer, ptr);
const ref = new interop.Reference(type, ptrToPtr);
return ref.value;
}
onmessage = function(msg) {
var dict = valueFromPointerNumber(NSDictionary, msg.data.value.dictionaryPtr);
// decrease reference count
dict.release();
} While trying to make it work I discovered a bug in the runtime which is currently preventing the above code to work on 64-bit devices and Simulators. But you can test it for example on an iPhone 4s Simulator ор device. After we merge the fix it will shortly be available as a @next version of tns-ios. To use it you'll have to install it with |
@mbektchiev thanks a lot! the same technique was proposed on android. Will try it soon to see if it work. |
No problem. Tell us if it works out for you after you try it. I forgot to mention something else which is very important -- to correctly keep the native object alive you'll have to call |
@mbektchiev is the fix already released for your code sample to work? Finally had the time to test this. and in the worker code the EDIT: it works! will share an example here really soon |
@mbektchiev as explaned before i got it to work. Now i am facing another issue.
Right now this is an issue because of memory management, so i have to "clone" the image in No real question here, just kind of brainstorming. Does anyone see a way of directly going to the worker? EDIT: sample code is the demo of the plugin i am working on. |
Why do you need to clone it on the main thread. Can't you follow the advice in https://developer.apple.com/documentation/avfoundation/avcapturevideodataoutputsamplebufferdelegate/1385775-captureoutput?language=objc:
|
@mbektchiev right now i use OpenCV CvVideoCamera for easy testing/dev The mat that is passed in |
This allows for correct serialization of pointers through strings. Which can be used for passing native objects to workers as discussed in #620 (comment). The need for these methods arises from the fact that `toNumber` can't be used for negative pointer values, due to JavaScript's values inability to represent very large and/or negative 64-bit integer values as integers. There is a real-world use-case for the value of `-1` shown in #921
This allows for correct serialization of pointers through strings. Which can be used for passing native objects to workers as discussed in #620 (comment). The need for these methods arises from the fact that `toNumber` can't be used for negative pointer values, due to JavaScript's values inability to represent very large and/or negative 64-bit integer values as integers. There is a real-world use-case for the value of `-1` shown in #921
This allows for correct serialization of pointers through strings. Which can be used for passing native objects to workers as discussed in #620 (comment). The need for these methods arises from the fact that `toNumber` can't be used for negative pointer values, due to JavaScript's values inability to represent very large and/or negative 64-bit integer values as integers. There is a real-world use-case for the value of `-1` shown in #921
@mbektchiev i think there is an issue with the // main
function postMessageToWorker(data) {
if (isIOS) {
// the clone makes the UI slow! No solution right now
const nativeDict = NSMutableDictionary.dictionaryWithObjectForKey(data, 'data');
const message = {
value: { dictionaryPtr: interop.handleof(nativeDict).toNumber() }
};
// increase reference count to account for `dictionaryPtr`
(nativeDict as any).retain();
worker.postMessage(message);
}
}
function postImageToWorker() {
const folder = knownFolders.currentApp();
const imageFromLocalFile = fromFile(path.join(folder.path, 'images/test.jpg'));
const imageSource = new ImageSource();
imageSource.loadFromBase64(imageFromLocalFile.toBase64String('jpg'));
const image = imageSource.ios;
this.postMessageToWorker(image);
} //worker
equire('globals');
import { isIOS } from 'tns-core-modules/ui/page/page';
function pointerTo(type, value) {
const outerPtr = interop.alloc(interop.sizeof(interop.Pointer));
const outerRef = new interop.Reference(type, outerPtr);
outerRef.value = value;
return outerPtr;
}
function valueFromPointerNumber(type, value) {
const ptr = new interop.Pointer(value);
const ptrToPtr = pointerTo(interop.Pointer, ptr);
const ref = new interop.Reference(type, ptrToPtr);
return ref.value;
}
(global as any).onmessage = function(msg) {
if (isIOS) {
const dict = valueFromPointerNumber(NSDictionary, msg.data.value.dictionaryPtr) as NSDictionary<string, any>;
const data = dict.objectForKey('data');
// decrease reference count
(dict as any).release();
}
}; |
Support for Workers
For Android solution please check - NativeScript/android#532
Description
General guidelines for the Workers implementation effort and specification in the context of NativeScript.
We have an existing issue here, but the purpose here is to show the road map that the team intends to follow in developing the Workers functionality. The general scenarios we want to support are listed at the bottom.
Limitations
In NativeScript we don’t need to implement all details of the web workers specification, because some of these details are only related to the browser, and won’t have any meaning in the context of a NativeScript application.
List of features we decided not to support:
The features and syntax that will follow has the purpose of describing the adoption of the web workers specification in NativeScript. In this document we will describe and list what we intend to support.
Guidelines from the specification to follow
context
messaging specifics
messaging transfer ownership
onerror spec
Syntax
The following example will be the general syntax to use when working with Workers. Syntax is based on web worker specification.
<app_name>/app/main.js
<app_name>/app/worker.js
Supported APIs:
Worker Object:
Worker Global Object:
WorkerGlobalObject.importScripts()We decided not to support it. Singlerequire
function is enough.Implementation steps:
onerror
handler of the worker object on the main threadCoreAnimation
APIs throw exception if UI operation is executed on a background thread. The exception is thrown inCFRunLoopObserver
installed by theCoreAnimation
framework. The exception is catched by the system and the runloop is not stopped. We can't place our code between the exception throwing and the exception catching, so we can't handle it in a custom way. However, the system logs a warning in the system log which will be displayed in the CLI output.The text was updated successfully, but these errors were encountered: