So, you actually can use threads. You're just limited to what Unity features you can call on threads that aren't main. If you simply want to do math, and are using data that isn't locked to integral Unity classes (structs, Game objects, etc), then thread away.
A threaded approach in unity often requires a bit of work to decouple your data from Unity and then find a way to re-inject it when applicable. When I have to do such things, I often use coroutines that act as thread watchers allowing Unity to utilize threads for both asynchronous and parallel applications.
an example of how do decouple something like a transform:
//this contains whatever transform data your threads need to modify.
//Initialized at start / GO instantiation
struct xform{
Vector3 pos;
Quaternion rotation;
}
//Allows you to move data from worker thread to main thread.
IEnumerator xformUpdate(){
while(runningCondition){
//only grabs data if it's available
if(readyForUpdate()){
//transfers data from xform to Transform
xformToTransform(args);
} else {
yield return null;
}
}
}
Obviously you'll need to implement your own systems to check if calculations are complete / ensure you don't run into data races.
The other big blocker is that your ability to use threads is very Unity version dependent. Unity 2017 (with experimental mono enabled) has access to tasking and parallel libraries that Unity 5.x does not. Both still have threading options available, but it's definitely worth looking into when developing your solution.