Threading -- background tasks

48 views
Skip to first unread message

guille.r...@gmail.com

unread,
Sep 1, 2017, 7:10:03 AM9/1/17
to PlayN
Hello,

I have some long running tasks that I want to run "in the background" (different threads) and periodically post results to the main game thread for UI updates etc.

What is the recommended approach for this?

(Note: I know that I could try to divide this task in small bits and run it on the main thread but for various reasons this is not practical. Also, I only need to support iOS and Android.)

Thanks,

Guillermo

Michael Bayne

unread,
Sep 5, 2017, 12:24:53 PM9/5/17
to pl...@googlegroups.com

--

---
You received this message because you are subscribed to the Google Groups "PlayN" group.
To unsubscribe from this group and stop receiving emails from it, send an email to playn+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

guille.r...@gmail.com

unread,
Sep 6, 2017, 3:26:07 AM9/6/17
to PlayN
Hi Michael,

Thank you for your answer. This takes care of communication in one way; what about the opposite direction? (i.e. how would the main thread message the background, "worker" threads?)

Perhaps with a more specific example:

I would like to use a background thread which talks to a server and performs some transformations with the received data (the control logic is somewhat complex so I would like to avoid the approach of slicing this work in small bits which are then performed in each frame.)
So this background thread can post updates via invokeAsync. However the main thread also needs to post messages to the background thread depending on user actions -- which data to retrieve from the server, which kind of transformations to apply, parameters to these transformations, and so on.

How would the latter be done? Are there any synchronization mechanisms / APIs available? Can I just use standard Java2 APIs? (I guess these would not work in the browser but I'm only targetting Android and iOS here)

Best,

Guillermo


On Tuesday, September 5, 2017 at 6:24:53 PM UTC+2, Michael Bayne wrote:
On Fri, Sep 1, 2017 at 4:10 AM, <guille.r...@gmail.com> wrote:
Hello,

I have some long running tasks that I want to run "in the background" (different threads) and periodically post results to the main game thread for UI updates etc.

What is the recommended approach for this?

(Note: I know that I could try to divide this task in small bits and run it on the main thread but for various reasons this is not practical. Also, I only need to support iOS and Android.)

Thanks,

Guillermo

--

---
You received this message because you are subscribed to the Google Groups "PlayN" group.
To unsubscribe from this group and stop receiving emails from it, send an email to playn+un...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Michael Bayne

unread,
Sep 6, 2017, 11:11:14 AM9/6/17
to pl...@googlegroups.com
I think you misunderstand how the threading system works in PlayN.

Exec.invokeAsync() is intended to invoke a single "job" on a background thread. When that job completes, it can post its result back to the main game thread using Exec.invokeLater() or using an Exec.deferredPromise().

There is no way (via the PlayN APIs) to start a long-running background thread which passes messages back and forth with the main game thread. Every time you run invokeAsync(), the Runnable "job" you provide will run to completion on an arbitrary background thread. Each platform controls the size of the thread-pool that runs these background jobs, but it's usually more than one background thread so you cannot rely on ordering of invokeAsync() jobs and each job *must* be isolated. It cannot communicate (via mutating shared variables simultaneously) with other invokeAsync() jobs or with code running on the main game thread.

The system is designed for you to structure your code as small units of work that are completed asynchronously. PlayN's HTTP code already runs asynchronously, so you don't have to run that in a background thread yourself.

So as a result of a user action which took place on a game thread, you could issue a Net.get(url) request (which will run in the background automatically), then listen for the response on the returned RFuture, then when you have the result, you can pass that data and whatever processing parameters you want into a Runnable that is executed via Exec.invokeAsync() and do whatever processing you need on a background thread, and when the result of that computation is complete you can deliver it back to the main game thread via Exec.invokeLater() to, for example, update the game UI, or whatever you need.

Android and iOS do happen to support most of Java's low-level thread primitives, so you could probably start your own threads and use whatever JDK classes you want to coordinate between them, but I recommend against it. Most video games use thread-pool-backed job systems like the one PlayN provides, and most modern application frameworks do so as well, because it is a *far* less fragile way to do multi-threaded computation than trying to manage threads yourself and coordinate multiple message queues and avoid deadlock, unnecessary blocking, etc.


To unsubscribe from this group and stop receiving emails from it, send an email to playn+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

guille.r...@gmail.com

unread,
Sep 7, 2017, 10:39:38 AM9/7/17
to PlayN
Hi Michael,

Thank you for the overview. Yes, this makes sense for one-off actions such as the one you describe: User performs action, then as a result I issue a Net.get(url), then process the response, then post the result back to the main thread, etc.

But in my case I am not talking about one-off actions -- there is a continuous conversation between client and server, which is influenced by user actions (but not completely dependent on them). Of course I'm not saying this cannot be done with the approach you suggest, but that approach forces me to split the work into small bits which is what I wanted to avoid. I am also aware of the complexities of (correct) multithreading.

I'll need to give this another thought and see how to tackle the problem.

Anyway now I have the information I was asking for :)

Thanks,

Guillermo

Brigt Vik

unread,
Sep 11, 2017, 8:57:16 AM9/11/17
to PlayN
This is not what you originally asked about, so I don't know if this helps you all that much, but in your last post it sounds sort of like what I do with my client-server communication. I collect messages that should be sent to the server. Both timed actions (such as a list that determines it needs updating from the server) and user actions (such as joining a game or making a move) can result in messages being added to this collection. When a timer has passed the threshold for server communication to occur, it converts all the collected messages to a string and sends them off to the server. In response, the server will usually send back a string containing a number of messages, which are parsed and passed off to whichever places in my code that have subscribed to those messages. To avoid concurrency problems, only one such communication can go on at a given time, if another would be started before receiving the response, it will be delayed until the next timer threshold and messages will accumulate in the meantime.

guille.r...@gmail.com

unread,
Sep 12, 2017, 4:34:28 AM9/12/17
to PlayN
Hi,

This would not work for my specific case (in my case, user actions need to be run as soon as possible, so it is not practical to queue them to be flushed together with timed actions), however it is always nice to see how other people have solved similar problems. Thank you for sharing!

Guillermo

Brigt Vik

unread,
Sep 12, 2017, 7:39:42 AM9/12/17
to PlayN
As you need instant communication I don't see any way around handling net communication in several places. Well, I guess you could still have some centralized component that dispatches messages according to subscriptions even if it does not wait to collect messages before sending. In my case, the client knows what should normally be happening upon a user action and can thus show a predicted outcome immediately. If the server disagrees (such as, you actually lost on time so won't get to make the move you thought you made in that last second), the client state will then be changed to match the server's opinion once that is communicated back.

By the way, you may find that pushing every single action separately could slow down communications somewhat - I think on Android at least, there will only be one request going at the same time. I've noticed this when probing which servers are active, if the first in the list is unreachable, the second probe won't go out until the first times out. Which is to say, if you're trying to send many messages separately in a very short span of time, it may take a bit for all of them to actually get sent. Note that this may not be a problem if you're using web sockets instead of the plain HTTP requests I'm using.

guille.r...@gmail.com

unread,
Sep 13, 2017, 11:30:46 AM9/13/17
to PlayN
Good point regarding multiple simultaneous requests. Shouldn't really be a problem in my use case but definitely something to remember.

I would like to move to websockets in the future but the initial implementation must be plain HTTP due to requirements that are beyond my control..

Guillermo

Andres Martinez Quijano

unread,
Sep 13, 2017, 11:37:36 AM9/13/17
to pl...@googlegroups.com
I have a working app with websockets (from ~5 years ago), probably not
perfect, but works, let me know if you are interested in it

guille.r...@gmail.com

unread,
Sep 14, 2017, 7:18:07 AM9/14/17
to PlayN
Hi,

Sure! I am currently in the learning state, getting acquainted with PlayN. There are not so many samples and demos available (or they are not easy to find) so anything I can have a look at will be more than welcome :)

Guillermo
Reply all
Reply to author
Forward
0 new messages