Solved: I did not know that the mathematics library had a random function, and in learning that I also learned that I need to be VERY careful on which functions/libraries I use with DOTS.
This works:
Unity.Mathematics.Random mathRandom = new Unity.Mathematics.Random(88);
int randomValue = mathRandom.NextInt(0, 10);
Also, while I haven’t done it yet, what EizenHorn states is worth looking into.
Hello gang,
I’m having an odd situation where I am creating a NativeList in a Job’s Execute and when I generate a random number number Unity hangs. Task Manager shows 0% CPU and the memory usage does not change. I left it running 10 minutes to see if there is any change to these values, nope. Had to End Task on Unity
int randomValue = UnityEngine.Random.Range(0, 10); //This line uncommented causes Unity to hang
public void Execute(
DynamicBuffer<AutoLanePointsComponent> autoLanePoints,
[ReadOnly] ref AutoDetailsComponent autoDetails,
ref AutoPositionComponent autoPosition,
ref Translation autoTranslation,
ref Rotation autoRotation)
{
var distance = math.distance(autoPosition.destination, autoTranslation.Value);
if (distance < reachedPositionDistance)
{
autoPosition.currentIndex += 1;
//If the current position is at the end of the list of points,
//if so, get the next list from the road/connection
if (autoPosition.currentIndex >= autoLanePoints.Length)
{
NativeList<int> roadIdents = new NativeList<int>(Allocator.Temp);
//autoLanePoints.Clear(); //Before we add new values...
//Get the next connection and it's points
if (autoPosition.isOnRoad)
{
for (int i = 0; i <connectionEntities.Length; i++)
{
var connectionDetails = ConnectionDetailsFromEntity[connectionEntities[i]];
if ((connectionDetails.LaneIdentity == autoPosition.laneIdentity) &&
(connectionDetails.RoadEntryIdentity == autoPosition.roadIdentity))
{
roadIdents.Add(connectionDetails.RoadExitIdentity);
}
}
if (roadIdents.Length > 0)
{
//int randomValue = UnityEngine.Random.Range(0, roadIdents.Length - 1);
int randomValue = UnityEngine.Random.Range(0, 10); //LOCK UP HERE
//autoPosition.roadIdentity = roadIdents[randomValue];
}
}
autoPosition.isOnRoad = !autoPosition.isOnRoad;
autoPosition.currentIndex = 0;
roadIdents.Dispose();
}
autoPosition.destination = autoLanePoints[autoPosition.currentIndex].value;
autoPosition.destination.y += autoDetails.yOffset;
}
float3 lookVector = autoPosition.destination - autoTranslation.Value;
if (math.all(lookVector))
{
Quaternion rotationLookAt = Quaternion.LookRotation(lookVector);
autoRotation.Value = rotationLookAt;
}
float3 smoothedPosition = math.lerp(autoTranslation.Value, autoPosition.destination, autoDetails.speed * deltaTime);
autoTranslation.Value = smoothedPosition;
}
Use Unity.Mathematics.Random for random in bursted job, but don’t forget that this is struct and copied by value. You should prepare some NativeArray of random’s with count equal worker thread count and pass this array to your job and after changing - update this array.
(based on something like this Mathematics.Random with in IJobProcessComponentData )
_randoms = new NativeArray<Random>(JobsUtility.MaxJobThreadCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
var r = (uint) UnityEngine.Random.Range(int.MinValue, int.MaxValue);
for (int i = 0; i < JobsUtility.MaxJobThreadCount; i++)
_randoms[i] = new Random(r == 0 ? r + 1 : r);
[BurstCompile]
private struct SomeJob: IJobForEachWithEntity<SomeData>
{
[NativeDisableContainerSafetyRestriction]
public NativeArray<Random> Randoms;
[NativeSetThreadIndex] private int _threadId;
public void Execute(Entity entity, int index, ref SomeData data)
{
var rnd = Randoms[_threadId];
//Do stuff
Randoms[_threadId] = rnd;
}
Here fast example why “just” passing Random to job and using it wouldn’t be a “good” random.
Just run parallel job, and set batch size to 1 for splitting work to different threads. And here result of this “random” in every Execute, not so random huh?
public class RandomSample : JobComponentSystem
{
private struct PrintRandoms : IJobParallelFor
{
public Unity.Mathematics.Random random;
public void Execute(int index)
{
Debug.Log(random.NextFloat(0, 1000f));
}
}
private uint _seed = 999;
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
Debug.Log("----------START---------");
new PrintRandoms()
{
random = new Unity.Mathematics.Random(_seed)
}.Schedule(5, 1, inputDeps).Complete();
Debug.Log("----------END---------");
_seed++;
return inputDeps;
}
}
What do you mean? Did you try eizenhorn’s code verbatim? They specifically use a batch size of 1 there.
The code you show specifies a batch size of 1024, which should mean at least that many are executed per worker batch, ergo you likely (for list size <= 1024) run every single iteration on one struct instance, and the Random instance itself would be mutated per iteration. If you’d have set the batch size to something lower, say in the range of 1 to 10, you’d see that many unique values repeated in the logs since each worker execution starts with the same (default) Random and subsequently produces a predictable value (as in it’s PRNG purely based off the generator state).
Were this not the case and Random fields are actually randomized outside user code… I would find that incredibly cursed.