The day that unity become thread safe, a man's dream

Did you ever tried to use threads in your code for unity? I have done, these days you can’t think of Advanced AI systems without thinking about putting parts of it on threads, why? think about it, an agent needs to do path finding, and at the same time decision making, well, you would want decision making on higher priority maybe, but that can take half a second for each agent, so you would prefer to handle path finding first and then start decision making, now you may say that we can use coroutines but the thing is that it is still on the main thread, meaning that much of your computer’s resources may not being used at all.
another example, I will speak about a pet project of mine, currently developing an AI sand box, started with node based grid system, restoring every type of data u need for a game in serialization is out of question, it will cause like gigabytes of data on hard drive (more can be found on my weblog : unityai.net). so you would like to keep the minimum data serialized with scene levels and the rest being calculated on the fly, one of the most important thing is line of sight and line of fire for each node, that is if you want to be able to do tactical decision making. Now, both of them are using line casts, and you would never want to do them on the fly time and time again when you are doing decision making, the sane approach would be to have a data lookup table so that when you need to test a node, you could simply look inside the table and get the result. how this effect us? think about it, you are starting a game, loading a level and as soon as the level is being loaded you would like to have your data there or at least starting the collection of data. You can still use coroutines but as i said it’s waist of resources on machine, so you would like to start a thread that is looping through every node out there and do the ray casts for you, and that is only LOS and LOF, how about finding covers? another sets of line casts, at least 8 on mid height for crouching covers and another 8 for full standing covers, if we have 4000 nodes (pretty low for these day’s games) that would mean 18 line casts per node, now we still would be able to do them on the fly for when an ai need to make decision and mark the node being processed but that would cause possible freeze on the agent till it is being done. So you would want to have to do those line casts on a thread that is adding data to a static class and later on agents can read these data but wait…
Line cast is part of unity’s engine and api, and …
yah :frowning: you can;t use them on threads GAH

I think the day that unity announce that these type of things can be done on threads i will have a heart attack !

1 Like

Where’s NPSF3000/skull xray dude when you need him to harp on about such?

2 Likes

Wall of text is wall’y

2 Likes

seriously, i wouldn’t consider that much line a wall of text but if it bothered you, i apologize

The problem is more the punctuation, grammar and paragraphing, as opposed to the straight out quantity of text.

Back to the OP, I’m not entirety sure making the engine thread safe would be in every ones best interest. Multi threaded environments can create all sorts of difficulties. Unity prides itself on being an engine that anyone can make any game in.

Making the engine thread safe would come at a performance cost. That cost would be mitigated by the benefits of multi threading in some situations, like the one you described. However there are still platforms Unity targets with only one core. So the cost of being thread safe there would come with no gains.

You can still farm out anything that doesn’t touch the unity API to different threads. I’m not sure how many games would actually benefit from other threads touching the API.

Not to mention that internally there’s plenty of threading, and you can do your own threading. You just have to push data or make calls via the main scripting thread. It’s a limitation, yes, but that’s not the same as threading being impossible.

1 Like

first of all, sorry for my English problems, I’m not a native English man, but i agree with you that some of the platforms are single core, but should it restrict us for somethings to be possible? I mean, if someone is targeting mobile, he already knows that he should not use something like line cast on threading, but if he is targeting pc, why not being able to choose between using it on thread or not? As much as I know, the most important things for games like FPS TPS, is line of sight and fire for making proper tactical decisions and they only need line cast and ray cast stuff, provided, those two may need to make the whole physics engine thread safe, but I assure you, the day will come that Unity developers may need to consider this just so that they don’t fall on the development speed of other engines, question is, why wouldn’t they start doing something about it now instead of when they are forced to by the nature of industries?

From reading more of the text above, why do you need to do all of your calculations based on the data directly in the scene? A couple of considerations.

First of all, the representation in the scene isn’t necessarily the best representation for your AI making decisions or other potentially heavy workloads. For my heavy AI I make specific data structures optimised for the data they need and the decisions they’re making with it. Once I’ve got that data structure making it safely accessible to another thread is pretty easy (as it’s probably read-only for the most part), and I typically want to assign any new commands at the start or end of an update cycle anyway so going via the main thread isn’t much of a downer.

That brings me to the next consideration, which is that being able to access things in the scene willy nilly from other threads complicates both your work and Unity’s - you have to not accidentally trash shared data, and Unity doesn’t have to work around your access to said shared data (which can be a major) performance issue if it’s not handled well).

2 Likes

ok, first of all, we are on same boat about collecting data on needed structure and making it available for other systems in game, but i think you didn’t get the point, first take a look at this article anout alien swarm :

http://aigamedev.com/open/review/alienswarm-node-graph/

How many nodes are there? I bet more than 8000, if you put node positions, their connections, AND the visibility into a serialized file, even with protobuf that is making nice serialization sized you would end up with hundreds of megabyte of data for single game level !

so one way or another, you would want to collect these data at run time, with near 8000 nodes it may take up to 30 seconds for COLLECTING those data, the data structure and how you present them to other systems in not the question here, the collecting is. All you are arguing about is that it can be done in main thread and I know that, as I said in first post I’m not ignoring the ability to use coroutines, but using main thread mean that :

1- You are ignoring more cores that are available for those calculations
2- You are dividing the main core resources that maybe very much needed for stuff like rendering etc
3- You are limiting the whole system until those co routines finish their jobs

so, as I said many times by now, the question is not about IF there is no core, IF you can do something this or that way, the question is about NOT being able to do more stuff WHEN you can there is enough hardware resourced to do it. The AI situation that I presented was only and example of many other things that is getting on the way. Any part of unity api will not run and through errors telling that this or that should be done in main thread, that means that you are restricted lots of times from using processors available, specially in heavy parts of the game making that NEED unity API

No, I’m just not assuming that more cores will make things magically faster. I get where you’re coming from, I just don’t imagine the performance benefits will be as big as you clearly do.

Edit: I’m also not seeing the issue with accessing 8000 nodes that have to already be stored in the level data anyway. Why do you see making them separately available to your AI system chewing up hundreds of megs of extra data somehow?

very simple, because i’m speaking from experience and already tried it, and don’t even think I didn’t optimize it on serialization, when you sit and think, each point has a vector 3 as coordinated means 3 * 32 bits,

now, for each node we will consider 30m radius a rough distance to keep track of visible nodes, for 2m node gap = 15 node in each radius means that you will have a look up table of 225 nodes

multiply it by 96 bit per node position roughly = 21 kb / node and multiply it for 8000 node roughly = 167 MB just for visibility table sir , simple math there, roughly same amount for the line of fire makes it near 335 MB ! and that is only for position, that’s if we ignore the fact that we need to convert back that position to node it self to get more data reading.

if you instead use guid as visible node ID in the table, you get 16 byte / node because guid is 16 byte data structure type, in other words, not only you didn’t reduce the size but you couldn’t solve the look up for the node finding in future too. So, instead of blindly arguing with me, sit back and if you don’t want to bother trying, at least accept a man’s words that HAD already tried it in many different ways. Hell I even thought about representing the node visibility and line of fire in single chromatic textures and even int structures but even that wouldn’t help as much as you think it would. Long story short, these type of things can’t be done in a short cut fashion more than what we all know possible. And as I said, instead of clinging to my AI example, think about many other possible times you can use api on multi threading.
Also, I never said using multi threading would magically speed up every thing but, is there anyone out there that can argue about multi threading is not being useful in game programming and design these days?
If you want to still continue arguing about that AI example, I won’t comment any more simply because I know the facts and worked on them and there I don’t see any more point in arguing on that.

You can use multithreading for all your logic however you want. The limitation is that you have to serialize back the results if you want to pass them to Unity APIs.

Why is a node 21kb? It’s a position and a list of other nodes. I get 12 bytes (position) + 60 bytes (4 byte reference * 15). Even with overheads that’s nowhere near tens of kilobytes. What am I missing there?

1 Like

Just a wild stab in the dark @Jiraiyah ; Have a dictionary(dictionary A) of all the nodes (8000 Vector3’s (value)), with a key of type ushort(0-7999) call it the instanceID. Then have another dictionary(dictionary B) that contains the same 8000 instanceID’s(as key), with the value being 225 ushort values(as an array).

Then, once you determine your starting node and you know its InstanceID, you lookup its corresponding nodes from the dictionary B. Then for each of those nodes you can cycle through and do a dictionary lookup on dictionary A for each of them, and so on.

All you need to do is store and serialise this beforehand, JSON.net or something.

EDIT: It should reduce the size of your initial data storage.
112KB for dictionary A (8000 * (12 bytes + 2bytes))
3.616MB for dictionary B (8000 * 225 * 2bytes + 16000(for ushort))

1 Like

honestly, they should make multithreading way harder so fewer people think they need it.

ie: you need to have multiple threads running raycasts in order to run ai code.

sorry to be a grumpy old man, but of all the developers i’ve seen try to write multithreaded code - only maybe 1 in 10 actually knows what he’s doing. the rest are just fucking disasters, and would generally be much faster single threaded due to terrible lock strategies: ie: lock everything all the time because we have no idea whats touching the data when or where.

Or actual real deadlocks under simple small scale conditions!

5 Likes

This, or make sure you’re using a good data storage strategy to where you can you are using your other worker threads to update the data and do your calculations and store them off, then just accessing the storage from your main thread using a component. Then no serialization would be necessary as you’re essentially using your “storage” object to maintain state between your other thread and your main game thread.

This is so very true, and multithreading gets abused. One good example is Microsoft’s new(er) Parallels library for doing PLINQ. You see people doing parallel foreach loops when the actual operations on each element are literally like nanoseconds and far more time is wasted on thread management by the CLR than if they had just either done their work in a single thread, or batched it across multiple threads.

Locking strategies and locking in general are also a very important point. Obtaining a thread lock is not a cheap operation. In order to make the entire API / Engine thread safe, there would have to be a lot of locking taking place to account for potential concurrency issues. This would slow down the performance of the entire engine, so much so that for the very few bits any individual developer would be using async operations, the costs of obtaining locks elsewhere would likely mitigate most of the gains. Not to mention, at that point they could only guarantee that the base API was thread safe… the second you add a third party component of any kind from the asset store, you lose any guarantee of concurrency.

While I love multithreading where appropriate… I think it would be extremely unwise to try making the entire engine thread safe. Why do you think the entirety of the .NET framework is not thread safe by default? Some things are… but many things are not. You have to implement and handle thread safety on your own.

On that note… it would be nice if it were possible to access the API from separate threads as a “do so at your own risk” type of scenario… but I wouldn’t want it to be thread safe by default.

2 Likes

this. In all honesty, I would say that if it seems like accessing unity api from other threads is a problem, then you probably shouldn’t be trying to write multithreaded code in the first place.

OTOH, we all had to start somewhere, and anyone who’s written a multi threaded system has probably written terrible multi threading code (mine was ungodly bad when i was first learning). It’s part of learning.

1 Like

that is exactly what I am doing right now, actually the things that I’m keeping in serialization is a bit more that just the position of the node, it’s a guid for node zone, the position, three lists for possible covers close by, a list of guid for neighbour nodes, well, the neighbour list and cover nodes can be optimized a little based visibility in neighbour case and covers on top of each other (crawling, crouching and full stand cover in same x,z coord don’t make sense you would only keep full stand one and remove the other two.)
but even with all these data still the size is totally acceptable, what I was speaking about was when you would like to serialize the LOS, LOF on the disk. That would cause huge amount.
also, two notes for you
1- Protobuf is much better than json for multiple reasons :
a ) it’s binary format so won’t use unnecessary size on disk for string formats.
b ) because it’s binary players won’t be able to hack to it easily
c ) it supports Unity by default
d ) it’s free
e ) it serialize / deserialize much faster than json
2- A proper look up table for node’s things would be like Dictionary <Guid, List> for each neighbour, in range, LOS and LOF tables, this way you won’t waist any extra time for finding nodes from ID or position of them.

Finally an answer that would make me double think the situation, knowledgeable answer, thanks sir, now I know why it would be impossible to think about the whole engine as a thread safe, that makes totally sense now.

That was exactly my point on first post sir, but your first part of the post makes me double think the possibility of it, but at least I would like to see little parts of physX being available from threads.

Won’t Unity 5 have to be thread safe with it’s new Multi-threaded Task System?

No, that’s for certain internal things such as culling, not user code.

–Eric