Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Upcoming background tasks support in Gideros: a quick example — Gideros Forum

Upcoming background tasks support in Gideros: a quick example

hgy29hgy29 Maintainer
edited June 2016 in Code snippets
So, suppose you made a game which loads a lot of assets during init, suppose loading all of these assets takes up to 5 seconds, during which gideros hasn't displayed anything yet, or if you took care of delaying your init code by one frame you may just have displayed a static image and launched a nice intro sound. Looks familiar ?

Now wouldn't it be better if you could display a progress bar while loading, or even better an intro to your game ? Async tasks in Gideros 2016.6 allows that, and much more!

Take a look at the following code:
Assets={}
Assets.count=1000000
Assets.base="sky_world.png"
 
--Set up a progress bar
ProgressBar=Pixel.new(0x000000,1,application:getContentWidth(),50)
local innerBar=Pixel.new(0xFF0000,1,application:getContentWidth()-10,40)
innerBar:setScale(0,1)
innerBar:setPosition(5,5)
ProgressBar:addChild(innerBar)
ProgressBar.setProgress=function (self,ratio)
 self:getChildAt(1):setScale(ratio,1)
end
stage:addChild(ProgressBar)
 
function loadAssets()
 local ts=os.timer()
 print ("Start loading assets")
 for i=1,Assets.count do
  Assets[i]=Texture.new(Assets.base)  
  ProgressBar:setProgress(i/Assets.count)
 end
 print ("Finished loading assets in",os.timer()-ts)
 -- Start our game logic here
end
 
Core.asyncCall(loadAssets)
--loadAssets()
Here loadAssets() is a dummy function supposed to take a few seconds to load assets. On my computer it takes ~2.2 seconds to run.

Without asyncCall(), ie loadAssets() launched at the end of main.lua, the progress bar is of no use: it is only displayed once all assets have been loaded, gideros seems frozen during loading.

With asyncCall() however, the progress bar show up immediately and advances nicely while assets are being loaded. Loading takes a little longer though ~2.8s on my computer. This is because gideros continues to run normally, giving priority to the game loop and running background tasks only on spare time!
+1 -1 (+14 / -0 )Share on Facebook

Comments

  • Awesome! @hgy29
    By the way, @hgy29 could you please take a look at ios Object C/ Swift - LUA bridge and bring to Gideros as a plugin?

    https://github.com/alibaba/wax

    With that plugin, Our Gideros will be more robust and strong!

    Thank for your hard work :)
    Coming soon
  • hgy29hgy29 Maintainer
    edited June 2016
    @vitalitymobile, you are talking about something similar to BhWax from @bowerandy ?
    http://giderosmobile.com/forum/discussion/1719/using-wax-for-easy-access-to-objective-c-under-ios-gideros/p1

    Maybe better try to contact him for that.
  • antixantix Member
    I'm eager to try this out @hgy29, great stuff :)
  • hgy29hgy29 Maintainer
    Yes, this is a long awaited feature: looking back into the forum archives, many people were awaiting for asynchronous texture loading. Background tasks solves this, and gives much more possibilities. I hope you'll like it.

    It will help making even better user interfaces, Gideros used to look jaggy/slow because of synchronous loading. I am convinced this feature will help attracting more people to Gideros.

    Likes: SinisterSoft

    +1 -1 (+1 / -0 )Share on Facebook
  • @hgy29 Yes, It is started by @bowerandy
    Coming soon
  • totebototebo Member
    @hgy29, this looks too good to be true. I can run anything in the background? At no cost of CPU? If so, game changer (literally).
    My Gideros games: www.totebo.com
  • SinisterSoftSinisterSoft Maintainer
    edited June 2016
    @totebo - yes and because @hgy29 implemented 'auto yield' (after being convinced to by me btw!) it really is easy to code for. Normally you would have to add Yield commands to stop processing and pass control back to the other thread. With the auto yield you don't have to worry about any of that.

    The co routines start once the main thread has finished - so the sooner you get them started and run out of code on the main thread, the better.

    There is a cost to CPU btw, but it is cycles that would otherwise have been wasted.

    Likes: totebo

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+1 / -0 )Share on Facebook
  • totebototebo Member
    All that sounds amazing. When is the build coming again? :)
    My Gideros games: www.totebo.com
  • SinisterSoftSinisterSoft Maintainer
    The bad news is that @ar2rsawseen 's internet connection is currently down and will be for a couple of days. As soon as he gets a connection and makes a build, we can test it on all the platforms, write a couple of demos for the new functions and make a release build.

    Likes: totebo

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+1 / -0 )Share on Facebook
  • XmanXman Member
    It seems pretty good!
    BTW,will it cause any side effects if update the UI in the background task?
  • hgy29hgy29 Maintainer
    It shouldn't cause any side effects, since in fact everything is run on the main cpu thread.
  • XmanXman Member
    Ok,since in one thread,then no problem will be caused by multiple threads.Thanks for the great job.
  • test29test29 Member
    What if the CPU is maxed out (for example on older devices with one CPU core)? On that scenario is co routine executed or it will wait for free CPU time for execution (will not be executed)?
  • hgy29hgy29 Maintainer
    @test29, Gideros will ensure that at least one slice of a background thread is executed, no matter if free time is available, and if multiple tasks are waiting for execution each one will get a chance to get executed.
    +1 -1 (+2 / -0 )Share on Facebook
  • SinisterSoftSinisterSoft Maintainer
    edited June 2016
    Good idea - at least then things will continue on devices that are framing out because they are being worked too much on then events. I was worried slightly about this too and was considering calling a tick of the routine on a slow timer just in case - nice to know I don't have to bother doing this now. :)
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • keszeghkeszegh Member
    edited February 2017
    i have a problem implementing async calls. please help.

    i'm trying to change my file loading function to work in an async way but simply putting the loading function into Core.async() did not work, still the app freezes while a file is loaded.
    my file loading function first calls another raw file loading function that has a zlib.decode part, then a json.decode part. then my main file loading function processes the table we got this way from the raw function.
    the freeze of the app happens in both the raw loading part and in the processing part.

    is it that zlib/json cannot work in an async way or am i doing something wrong? thanks

    edit: of course i start with a call of
    local file = io.open( path, "r" )
    file:read( "*a" )
    i don't know if this part freezes, but if only this would hang up my app, that would be still way better than it is now, as the other parts take up most of the loading time.
  • The async stuff works when main.lua has run out of code - eg when the events start.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • hi, @SinisterSoft, i don't understand your answer (or rather how it is an answer).
    i think my problem is that zlib.decode and json.decode is one line of code so there is no chance to async it in lua and probably parts of zlib.decode cannot run in an async mode even if it is within an async called function.
    it would be good if some native functions that can be expected to run for a long time (like zlib,json) would handle async-ing.

    btw my use case is that in my anim app e.g. there are 2 layers of looping animations running and with a press of a button on one layer a new animation should be loaded (from a zipped json file). and what i want is that during this loading the animation on the other layer should run smoothly all the time (it is updated at each enterframe event).
  • hgy29hgy29 Maintainer
    Hi @keszegh,
    You are totally right, async code can only be preempted at lua granularity, so if your decompression or json parsing takes longer than the spare time in the rendering loop, then it will lag.
    Modifying C-code of those native functions to allow them to be paused and restarted later looks not easy, it would have been a job for independent threads.

    An option would be to fragment your files so that you would load several small chunks of zipped json, yielding between each chunk.
  • keszeghkeszegh Member
    edited February 2017
    @hgy29, thanks, that's what i was afraid of. i can understand that making these functions async would be complicated. at least for json there is a lua implementation. is there also for zlib that one can use in gideros?

    splitting the files is not really an option, as these can be exported/imported by the user.
    on the other hand i could try to split inside a file into smaller chunks (e.g. each frame is jsonned and zlibbed separately).
  • muromuro Member
    edited February 2017
    Hi All and @hgy29,
    I attached the example project. My system shows incorrect times and i wanna remove compressed files after unpacking. What's my wrong?
    How can i benchmark and confirm async loading assets for both untar and gunzip example? Beside the gunzip method is too slow for large asset packs, Is there more efficient way? or should we just use for little files ?

    Thanks in advance :)
    rar
    rar
    asyncCall-untar-gunzip.rar
    2M
  • john26john26 Maintainer
    edited February 2017
    I tried running main.lua and it seems to unpack the tar file ok. I'm a bit confused as the program is running "gunzip" within main2.lua simultaneously with "untar" which is called via a coroutine from main.lua. I think it is better to put all immediately executable code in one file (eg main.lua). What do you expect the program to do? Is this an issue with coroutines or something else?

    Have a look at this example of how to do coroutines. It shows how to get two coroutines to run together "move" and "pulse". In this case I had to use yield commands but this is only needed if you want to run equal timesteps as would be needed for animation. In your case the yield statements are automatically generated (but it might be an idea to try putting them in manually)

    http://giderosmobile.com/forum/discussion/comment/48666#Comment_48666
  • muromuro Member
    edited February 2017
    Hi @john26,
    I want to unpack over ~7.000 assets in a single file with reasonable size and speed.
    But I noticed to misunderstood asyncCall coroutine aspect for different sprite jobs. You are right, no need asyncCall for the same unpack jobs. So I will just use untar method. Gunzip method is so heavy for low-end devices. Thanks for your explanation
  • keszeghkeszegh Member
    edited February 2017
    @hgy29, now i tried to async call a 'normal' lua function, but it also hangs up the app.
    does asynccall work properly with onenterframe events (Actually i need it to work with timer events)? or they are not part of the 'main thread', so if i want to async load a function, then all eventlisteners should be also rewritten to async called functions?

    edit: sorry, maybe i was wrong and it maybe works. still, it's no harm to ask these, the answers would be informative.
  • hgy29hgy29 Maintainer
    Not sure what you mean exactly... :)
    Event listeners are always called on the main thread. Actually the main thread first runs all lua files, then continuously process events of each frame.
    Async functions on the other hand run on the spare time of each frame, each call within its own coroutine so that they can be interrupted and resumed at will.
  • thanks, clear enough.
    as i made a mistake in my code, for a while i thought that 'main thread' might mean only the lua code that is not called by some event listener but run directly while running the program. i'm happy that i was wrong.
Sign In or Register to comment.