Async loading of custom resources

I think there should be a way to load a big data file without blocking the whole game (and while maybe providing the user with an animated loading screen or something else to do). You can currently use sys.load_resource(), but that blocks the Lua thread.

Good point. I wonder if we could make it possible to do io.open() on bundled custom resources? @Mathias_Westerdahl, @sven, can that be done?

1 Like

Maybe I’m misunderstanding something, but reading and writing to file handles in Lua is still sync. How does that solve the issue? Maybe a simple callback API could work.

Well, if you can use the io functions then you could spread the work over several frames quite easily. That kind of behaviour could be wrapped up in a small Lua module for reuse.

True, but that’s not real async. You still waste valuable CPU ticks waiting for I/O. Plus, you have no idea how much work should you do each frame.

The proper way of doing this would be either on a separate thread, with a callback/message when it’s done, either through non-blocking i/o each frame, something like:

function on_update(dt)
  while file:ready_to_read() do
    file:read_as_much_as_you_can_without_blocking()
  end
end

This is similar to O_NONBLOCK behavior, except you don’t need select() since you already have the game’s run loop. (that’s still assuming read buffers are big enough not to get filled in 1/60th of a second)

Yes, you’re right. I wonder about the feasibility of adding this though. None of the Lua io operations are async as far as I know and I think the underlying operation of a call to sys.save or sys.load is similar to what happens with normal IO operations. @Mathias_Westerdahl, @sven, @Ragnar_Svensson, what kind of effort would be involved in creating an async version of sys.load/save?

1 Like

What magnitude are we talking about, and would you really need to load such a big file on every update?

I just tried to read a 100 MiB file of random data to generate some stats for this scenario. The samples were taken on an iMac and may of course differ for other devices, but since mobile devices uses flash storage the cost of reading a resource once is relatively low seen over a period of a couple of seconds.

Read size (b) | time (ms)
100           | 292
1024          | 88
2048          | 73
4096          | 44
8192          | 28
16384         | 19
32768         | 15
65536         | 12
131072        | 40
1 Like

I must admit I didn’t really profile anything. My particular use case is about 1-2MB of JSON. I suspect parsing it might take longer than reading it, though.

Maybe it’s too much of a dev effort for shaving just a few frames (those ~20ms) off the loading time, I agree. As a JS developer, I’m used to being alerted by sync I/O, but I guess this time it’s fine.