Threading examples/samples/tutorials

Do we have any examples or tutorials that show how one uses threading in Panda3D? I’m specifically interested in file-writing operations, and model-loading.

The manual has some information–it shows the asynchronous model-loading functions,for example. However, it doesn’t provide any concrete, complete examples that I see.
Thus, I think that I know more or less what to do to implement asynchronous model-loading–but I don’t know whether I’m missing anything, or what caveats there might be.

As to file-writing, I gather that this is similar to Python threading–which I’m not familiar with. Indeed, it’s been a long time since last I worked with threading of any sort, as far as I recall (and that would likely not have been in Python), so I’m somewhat uncertain in the field in general.

I could look up how Python threading works–but I gather from the manual that Panda’s recommended threading system is different in small but unspecified ways. Thus I don’t know how applicable a general Python threading tutorial might be, or whether the differences come with any new caveats…

So hence my question: do we have any tutorials, samples, snippets, etc. that I could look at?

I assume you’ve seen this manual page?
https://www.panda3d.org/manual/?title=Threading

There are several ways to leverage threading in Panda:

  • By creating threads directly from Python. Of course, this won’t get around the Python GIL, but heavy C++ operations in Panda release the GIL; for example, your thread can be computing things or loading files while the main thread is doing the rendering. Consult the Python documentation for more information on this.
  • Using task chains. You can create tasks that are added to a separate task chain that Panda will run in a separate thread. All the usual caveats for threading still apply.
  • Asynchronous loading, which is straightforward and fully handled by Panda for you. This can be done by passing a callback to loader.loadModel and friends such as the Fireflies demo demonstrates. Note that while using a lot of callbacks can turn your code into spaghetti, a very elegant way to use asynchronous operations in Python 3.6+ is to use coroutines, which allows you to write asynchronous code that looks synchronous.
  • The multi-threaded render pipeline. This is fully automatic in C++, and operated by setting threading-model to CDraw or Cull/Draw in config.prc; this makes Panda operate the various stages of the rendering pipeline in separate threads.

I have indeed–that’s what I was referring to when I said that “the manual has some information”, I believe.

So, if I’m reading you correctly, a normal Python threading tutorial should be sufficient to teach me what I want to know for this?

The manual indicates that Panda’s threading module differs from Python’s in some ways–what are those ways? Are they just minor differences in parameter-lists, or are some things handled differently, or do they have a different set of caveats?

Interesting; I’m not familiar with those. (And it’s been long enough since I looked at threading that I don’t recall “all the usual caveats” offhand, save for race conditions.)

Looking at the manual page for task chains, I’m not sure that these are the best choice for my purpose: I don’t intend to use threading for anything that’s repeatedly run. I could, of course, just give the task-chain a once-off task, but that feels awkward–and additionally, it looks like I’d want to have some means of keeping track of available task-names in case the threaded code is repeatedly called. (As calling the chain setup method with the same name results in the previously-made chain being re-configured, rather than a new chain being made.)

I suppose that I could keep a task-chain around in the background to be used, and add a “do-later” task to it as called for…

That’s good to know. :slight_smile:

Ah, thank you! I’ll likely check that to get an idea of how to properly use asynchronous loading. :slight_smile:

Eh, in my case I’m not too worried: I only intend to use this in one place (level-loading), and the process is fairly straightforward. It shouldn’t result in too much mess, I think.

Still, thank you for mentioning coroutines; I appreciate the information. :slight_smile:

I’m aware of this–but it’s not really applicable to what I’m trying to do, I think. ^^;

Python threads aren’t fundamentally different with Panda, so the same documentation for using threads in Python should apply. Of course, you need to synchronize access to your own objects. Most of Panda’s own objects are synchronized with locks, so you can eg. manipulate a NodePath safely from two threads, but not all classes, so it is generally advisable to transfer ownership between threads where needed.

Task chains are just a convenient way to schedule tasks on a thread; if this doesn’t fit your usage pattern, then don’t use them. Note that tasks are also useful as a one-time fire-and-forget task; in fact, the loader maintains its own task chain to use for operations like asynchronous loadModel.

If you use coroutines, using the task manager is a must, since you have to add coroutines to the task manager. But they don’t need to run more than once, and in fact, you can pause coroutine tasks waiting for other things to complete.

Fair enough, and thank you on all points. :slight_smile:

I’ve started working with the (Panda) “threading” module for now–at the moment it’s the approach that makes the most sense to me for what I’m doing.

It’s entirely possible that a task-chain approach would be simpler, or more efficient, but for now, given that I’m not all that comfortable with threading, I’m going to stick to the approach that seems, at least, to best fit my intended logic. ^^;

Thank you for your advice here! :slight_smile: