Download

Is Threading what I think it is, and what's up with Async?

From what I understand on threading, I’m running stuff on a different slice of the processor so I can have two or more things running simultaneously without slowing down my game.

For example, in a city simulator, I could calculate traffic on a separate thread so that it doesn’t slow down the main Ticking process and thus not increase the time to calculate each frame; in an RPG, I could have characters walking around and deciding what action to do next on a separate thread for the same effect.

I understand that is a very basic view of it, but is the general idea the same? I run calculations or whatever I would normally do in a Tick() function on a different thread, with the outcome being each frame I’m not waiting on those calculations before presenting it to the player?

As for Async, according to this forum thread, it’s getting the same effect but having to write a bit less? Or is it better, or worse, or otherwise just different​?

Yes, that’s exactly right. Using threading you can delegate a time consuming task to another thread than the main game thread. The reason why this is important is because doing work on the main thread will block it. For an very simple example, imagine this function in an actor class:



void Tick()
{
	Sleep(1);
}


This will make your game literally unplayable! Doing expensive calculations on the main thread has the same result.

Async means non-blocking. In other words, if you fire off ExpensiveCalculation(), your calling function will continue without waiting for the result. People often use async as a synonym for threading, though async code doesn’t HAVE to be implemented using threads (see concurrency vs parallelism).

In Unreal you can assume that Async<T> and FAsyncTask<T> are implemented using threads. They are abstractions over threads so that you don’t have to do the (low level, error prone) work of managing threads.

Neat-o.

Do I need to worry about the number of threads/assigning my Async<T> to a particular thread? For example, in the RPG (or I guess more Sims-like), I could have twenty different actors deciding what they want to do next - sit down and eat, talk to someone, etc. I couldn’t run each of their decision-making processes on different threads - I’d need at least twenty threads, and isn’t there one thread per CPU (unless they are hyper-threaded?) So, would I assign all these “What do I do next?” calculations to Thread n​? Or do you just infinitely cut up threads into more numerous, smaller (less performant) threads?

I have a wiki on Multi-threading here:

:heart:

Rama

There definitely isn’t a restriction of one thread per CPU, or even per (hyperthreaded) core :slight_smile: For example Process Explorer is telling me that the Firefox process I’m typing this in is has 81 running threads right now. Though that doesn’t mean you should just fire off 20 threads if you have 20 jobs (in fact, it’s very unlikely that you would want to). Threads are relatively expensive, both in memory usage and time needed to create one. The prime number computation on the wiki Rama linked is an example of a task that’s a good fit for a thread: it’s long running, can fully utilize a whole CPU core, and there is only one instance of it.

If you have a bigger number of jobs, that are not necessarily extremely time consuming (but enough so that you wouldn’t want to run them on the main thread), you generally want to use some sort of thread pool system that will distribute the work over a number of threads that is a good fit for the CPU. I have to say I have little experience using Async in UE though. From the name ThreadPool sounds like what I’m talking about, but according to the page you linked it runs the jobs one after another in a queue (I’m having trouble coming up with a scenario where that would be useful). In C# there is an excellent task system that will distribute the work evenly over cores and allows you to fine-tune parameters for the jobs if needed. TaskGraph sounds like it is the closest fit to this (though I don’t know how the engine schedules and distributes the tasks internally). You may also want to check out FAsyncTask (AsyncWork.h) which I’m more familiar with from the audio decompression code, but I can’t make any recommendations as to which would be a better fit for gameplay code.