android
android copied to clipboard
questions about background threads
I know you already said here that all JS runs in UI Thread but i would like to have another look at this. The reason is that i found out that on IOS the Js code will run on the the thread in has been triggered. This is actually an amazing feature. Thanks to that i managed to create an OpenCV module that can do live camera processing. In native the image processing is triggered from a background thread, then i call a JS delegate that modifies the image and returns it. All that happens in the background thread!.
It works amazingly. Imagine all the possibilities! Now obviously i want to look at this on android. I immediately faced a wall on android as the runtime will always make sure the call to v8 JS will be done on the "worker" thread. I wanted to try things so i decided to debug the runtime and modify the code so that it runs the v8 JS in the thread it is in. To do that i simply modified the code to make it believe it is always in the worker thread Now i get a weird error that i dont get. I end with a maximum call stack exceeded:
Process: org.nativescript.demovueopencv, PID: 2587
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:354)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Caused by: com.tns.NativeScriptException:
Calling js method doInBackground failed
RangeError: Maximum call stack size exceeded
File: "file:///data/data/org.nativescript.demovueopencv/files/app/vendor.js, line: 39669, column: 14
StackTrace:
Frame: function:'ActivityCallbacksImplementation.onStart', file:'file:///data/data/org.nativescript.demovueopencv/files/app/vendor.js', line: 39669, column: 15
Frame: function:'NativeScriptActivity.onStart', file:'file:///data/data/org.nativescript.demovueopencv/files/app/vendor.js', line: 37027, column: 21
at com.tns.Runtime.callJSMethodNative(Native Method)
at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1162)
at com.tns.Runtime.callJSMethodImpl(Runtime.java:1041)
at com.tns.Runtime.callJSMethod(Runtime.java:1028)
at com.tns.Runtime.callJSMethod(Runtime.java:1008)
at com.tns.Runtime.callJSMethod(Runtime.java:1000)
at android.os.AsyncTask_bundle_283_42_AsyncTaskRunner.doInBackground(Unknown Source:20)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
... 4 more
It seems to appear in the native side which i dont get. Can someone guide me on this?
actually after a little bit of research it seems possible to run v8 in a multi thread environment using v8:locker. see this commit
Holy cow. That opens up a ton of possibilities. I once looked at writing a simple module that would run any block of code in a worker when passed to it. This is exactly the thread solution I had in mind. Super curious to hear more and dive into this myself.
@farfromrefug - I looked at that commit you linked to; I think you might be confused on a couple points about how the v8 engine works and maybe how the Android OS works.
-
Each NS webworker (and also the main thread) are separate isolates running on separate native threads; this is how the webworker can do its work separately from the main thread. In the v8 engine anytime you have separate working JS code it requires an Isolate.
-
The main v8 thread actually runs its JS isolate/engine on the main application thread because Android requires all UI work to be done on the main thread. You attempt to do any UI (and some others things) off the UI thread; your app will crash. No getting around this EXCEPT if you are using OPENGL to do the interface, then the opposite issue occurs all OpenGL must be on a separate thread; but again certain other actions still have to occur on the main thread in the Android OS. For example all system wide callbacks always are forced to the main thread by the OS. This is the primary reason why OpenGL can't work from the JS engine in NS on Android; the primary isolate forces everything back on the main thread so that it can work properly when talking to any UI objects, but opengl requires it to be on a separate thread (same thing with network actions, this is why the network objects in Android NS are Native Code so that the actions occur in a separate native thread).
-
The "Locker" system allows sync'g between two threads on a isolate; but does NOT allow the isolate thread to be running on two separate threads at the same time; all it does is allow a thread to pause and wait for another thread, See:
/**
* Isolate represents an isolated instance of the V8 engine. V8 isolates have
* completely separate states. Objects from one isolate must not be used in
* other isolates. The embedder can create multiple isolates and use them in
* parallel in multiple threads. An isolate can be entered by at most one
* thread at any given time. The Locker/Unlocker API must be used to
* synchronize.
*/
(quoted from: https://github.com/v8/v8/blob/96a039aab14b71069e88c4c04543e6bc9514a0d6/include/v8.h#L7237 )
One note; if you allowed the main thread to run on another thread besides the UI thread (i.e. eliminating the force to main thread that currently occurs; then all assumptions in the NS core modules about where things are running would cause it to crash very quickly. The TNS core modules assumes when it sets the color of a button, it is running on the UI/Main thread, when TNS core modules handles a click; it assumes it is on the UI/Main thread. To make this cross threads compatiblewould require a LOT of reworking off the TNS core modules and would actually slow the app down because of all the checks to make sure that the next set of calls it did were on the UI thread when it needed to access anything UI (which occurs very frequently).
@NathanaelA not confused I think. I know about mentioned and handled it quite a bit in a previous framework. now the point here is that it is doable and would open like a huge door. IOs already does that and it is doable on android (lot of work though). and there would be easy way to make sure some methods are called on the ui thread (like decorator)
@farfromrefug - I could be wrong; but based on what I know of the v8 engine, Android OS and the way nativescript works -- I honestly don't think you can do what you want without there actually being a significant consistent performance hit. But, I would love to be proved wrong; as this would make somethings easier to do. ;-)
@NathanaelA Actually the performance hit is happening without it. Because everything needs to be run on UI Thread, for example android lifecycle callbacks. The only draw back will be the need to check for UI thread. The rest is already done (sending a message to the ui thread to run the JS callback there). Also this will mostly never be an issue as almost everything within {N} already is running in the UI thread on the java side