Best approach for long computations, threading or timeslicing?

Started by
8 comments, last by Adehm 8 years, 9 months ago

I have a number of long calculations that I need to perform regularly in a realtime game. Currently, I try to avoid stuttering by timeslicing them. But, it can be tedious to split up the code in blocks that can perform below the time limit and it also introduces complexity in the algorithms.

Are there any better approaches? I have thought about creating worker threads instead but it seems like I would just have to deal with a whole new set of problems.

Advertisement

The choice of the approach is really down to which compromise you want to make. Your choices are really as you identified

- Time slice so need to split up your code into small chunks that fit into a slice

- Threads can require complex and costly locking to remove the risk of strange race condition bugs or data shifting under you, a pain the the arse to track down as normally hard to reproduce.

The thread option is probably easier to scale over multiple cores to make better use of the hardware.

Or do both. If you can separate things into truly separate chunks, you can do that _and_ batch those out to a task/job system, giving you greater CPU utilization and faster computation.

And doing threading with a proper job system removes the scary thread synchronization issues that WozNZ alludes to and avoids the fears you have with worker threads (which are used under the hood by the job/task system) because you should for the most part be agnostic to the fact that threads are even in use. So long as your jobs don't have crazy shared mutable data, there's no need to ever go near a thread synchronization primitive outside of the low-level job system itself. smile.png

If all that seems to scary or complicated, there's always to good ol' fork-and-join model, which is usually where I recommend people start out if they're new to threading.

Sean Middleditch – Game Systems Engineer – Join my team!

In this day and age, I would suggest to just make them async. Be careful of dispatching new work faster than they get processed.

In theory I would suggest std::future but it is my understanding it has no "is result ready" call so I'm afraid you will have to go with std::thread.

Now, you should carefully approach threading but you don't have to be scared by them. In a certain sense, they don't introduce really new concepts in terms of data safety. Just try to figure out a minimal data set they need to work on and the minimal "interface".

EDIT: SeanMiddletech reported below that it is possible to obtain a "is result ready call" by having a sleep-by-0-seconds call. I consider it a bit quirky but it sure will do. Go upvote that post.

EDIT: I have noticed WFP reply is more recent. Whoops. Go upvote that as well. Note: use the quote button, it gives notifications to the quoted person.

Previously "Krohm"


In this day and age, I would suggest to just make them async. Be careful of dispatching new work faster than they get processed.

In theory I would suggest std::future but it is my understanding it has no "is result ready" call so I'm afraid you will have to go with std::thread.

Does the OP say he needs an "is result ready" function? It's unfortunate that the std::future is missing a typical feature, but you don't always need that function. Whenever I have used jobs, I have not needed to poll for when they are finished. I just put the wait where the result is needed.

I agree there are likely better approaches, but in case an "is result ready" is needed for a std::future you can call wait_for on your future with an argument of 0 (no wait) and compare the result to future_status::ready. See the below link for more information and example usage.

http://en.cppreference.com/w/cpp/thread/future/wait_for

In theory I would suggest std::future but it is my understanding it has no "is result ready" call so I'm afraid you will have to go with std::thread.


http://en.cppreference.com/w/cpp/thread/future/wait_for

Give it a zero duration and then check the result.

Sean Middleditch – Game Systems Engineer – Join my team!

I use both in my game. A multi-threaded job scheduler with jobs which process data in a timesclining manner. And worker threads working concurrently to the rest of the engine.

I prefer the job scheduler, because of more control of what is processed and when it is processed. I'm still struggling with concurrently workers and the difficulty to load balance them on the available cores without risking performance break-ins.

Regardless of your choice you still have to slice up long jobs into smaller ones to get better responsiveness. This is a little easier in the threading case as you can always yield the thread at any convenient point. So with that in mind I'd think threading is the way to go. It should be both easier and more efficient once you get the swing of it.

This is my thread. There are many threads like it, but this one is mine.

Threads work great if you need to run complex calculations with a simple return. Always be weary of using a thread to return complex data because it could take more time to send and return then it saves.

Do these calculations have to happen every render? If not break them down into sections. For example I run an AI by having it make decisions throughout multiple renders.

1.What do I want to do

2.Where can I move

3.Where should I move

4.Begin Move

This way the framerate never drops even though the AI made a complex decision.

This topic is closed to new replies.

Advertisement