TiForward / discuss

By the Titanium™ community, For the Titanium™ community
http://tiforward.org/
103 stars 1 forks source link

Async approach (low level architecture) #4

Closed yuchi closed 7 years ago

yuchi commented 9 years ago

Currently, with Kroll, the JS VM lives in a separate thread. As far as we know in Ti.Next we’ll have JS running on the main (UI) thread. In Node/io.js we have libuv to work with other threads.

Which is the actual direction we’ll take?

cb1kenobi commented 9 years ago

I think the JS engine has to run on the background thread. If it ties up the main thread too much, UI becomes unresponsive and worse yet, iOS will kill your app.

We should be focusing on making the Titanium API async friendly similar to Node/io.js. This means providing sync and async versions of many system functions.

Next provide APIs such as promises, generators, streams, and event emitters. Each of these can be transcompiled down into ES5 and thus work in JavaScriptCore.

Yes, libuv has threads, but that's mostly for the async disk io stuff. The main event loop is not multithreaded. libuv doesn't have a very flexible way of inter-thread communication. You basically can only send a task to a thread and listen for a result.

yuchi commented 9 years ago

We should be focusing on making the Titanium API async friendly similar to Node/io.js. This means providing sync and async versions of many system functions.

What‘s good in Node.js/io.js is not only the included APIs itself, is the fact that you can do that in user-land. This last part is my biggest concern.

Next provide APIs such as promises […]

I know you love cps (:stuck_out_tongue:) but we could use promises/futures as the pillar of one-shot async behaviour instead of callbacks. Don’t consider it a real must-have, more of a nice-to-have-for-future-proof-APIs thing.

[…] The main event loop is not multithreaded […]

Missed that.

[…] You basically can only send a task to a thread and listen for a result. […]

So it’s good for promises/futures and tasks, but not for streams or retained event based processes. No WebWorkers, in other words.

Did I get it right?

cb1kenobi commented 9 years ago

@yuchi Correct, libuv is fine for WebWorker-like things as well as async disk I/O (which doesn't really exist).

libuv simply spins up a thread to run a task and let the main thread know when it's done. If you look at https://github.com/nikhilm/uvbook/blob/master/code/queue-work/main.c, you can see uv_queue_work() gets called from the main thread which invokes fib(). I believe this takes a thread from the pool and has it run fib(). Once all of the tasks have been complete, it fires after_fib(). So, it's really an API designed to go do something async (like faking async disk I/O) and let me know when it's done.

Promises are just a completion notification mechanism and can be implemented in pure JavaScript. No need for any libuv-like APIs to implement this.

jhaynie commented 9 years ago

I'm not fully convinced based on performance measurements that Matt and I did that running in background thread vs. main thread is really a big issue. Most long running APIs like network will automatically do this in the platform layer anyway. I'm not opposed to continuing to do this background thread and HAL is designed to be thread-safe (also from a JSVirtualMachine basis) so we can certainly do this. One of the nice parts of running on the main thread is that it's much less context switching overhead.

I'm not entirely bought into having to have an event loop ala libuv / node. I'm not entirely against it either. Right now in the Titanium API (unlike node), we don't have a ton of async patterns for our APIs. so not sure how much we would benefit until we starting addressing that.

mattapperson commented 9 years ago

@jhaynie my instincts tell me that an async API would allow for better UI performance. But I have no facts to back that up, so it's just a hunch. Might be interesting to test out though.

jhaynie commented 9 years ago

UI must always been on the main thread in all scenarios. So the question is in a normal Titanium app how much non-UI code which is not already normatively async (such as Network, Analytics, etc)?

What I think would be a sensible approach is to test both in some way. We'd need some sort of representative test bed and then test it. Most iOS apps people build native never use a background thread in my experience. They do only in cases of truly long-running tasks such as Network tasks -- but those APIs (such as CFNetwork) already handle that.

yuchi commented 7 years ago

Closing for obsolescence