Performance issues with threads and other things, duplicate Thread.Start()s?

I moved every possible thing into 3 separate threads, but the main thread is still very slow and looking at the profiler, the main cause is Thread.Start(), but it always shows two sets of Thread.Start(), and both take the same exact amount of time, so it’s like a duplicate thread runs whenever thread.start is called.

So I disabled all but one thread.start that I know for a fact NEVER gets called twice in one frame, and it still shows two separate instances of Thread.Start() happening in a single frame. (I am only at maximum launching three threads at once, but it would be rare, most of the time there should only be one thread.start in any given frame)

It is so frustrating to put everything on another thread and it is still slow. My game is fairly simple and doesn’t even have proper physics so maybe I’ll just learn OpenGL or Vulcan or something.

This is where all the threads are started (below). I’m not an expert but could it be that I am using lambda functions and passing a bunch of parameters to the thread? I hope that is not the issue because I have no other choice but to pass data to the thread because Unity classes aren’t thread-safe. Ideally, this whole thing would be in another thread but I’ve got to break it apart and leave flags for when threads are done because Unity.

private void Update()
    {
        if (generateNewChunks)
        {
            if (sortChunksToGenerate)
            {
                Vector3Int playerPos = Vector3Int.CeilToInt(player.transform.position);
                sortingThread = new Thread(() => SortChunksToGenerate(chunksToGenerateCounter, playerPos));
                sortingThread.Start();
                //SortChunksToGenerate(chunksToGenerateCounter, playerPos);
                sortChunksToGenerate = false;

                chunksToFillKeys = new Vector3Int[chunksToGenerateCounter];
                chunksToFillScripts = new Chunk[chunksToGenerateCounter];
                chunksToFillKeysCounter = 0;
            }
            if (sortingComplete)
            {
                GenerateChunkFromQueue(chunksToGenerate[sortedChunksToGenerate[chunkQueueCounter].a]); // if only this could be multithreaded too
                chunkQueueCounter++;
                if (chunkQueueCounter >= chunksToGenerateCounter) // using chunksToGenerateCounter because it might be less than the batch size but is always set to the batch size if not
                {
                    startingThreadsThread = new Thread(() => FillChunksThread(chunksToFillKeys, chunksToFillScripts, chunksToFillKeysCounter));
                    startingThreadsThread.Start();
                    //FillChunksThread(chunksToFillKeys, chunksToFillScripts, chunksToFillKeysCounter);
                    chunkQueueCounter = 0;
                    generateNewChunks = false;
                    sortingComplete = false;
                }
            }           
        }
        else
        {
            manageChunksCounter += Time.deltaTime;
            if (manageChunksCounter >= manageChunksFreq)
            {
                if (!checkingForNewChunks)
                {
                    Vector3 playerCameraPos = playerCamera.transform.position;
                    Vector3 playerCameraForward = playerCamera.transform.forward;
                    checkingForNewChunks = true;
                    checkDictionaryThread = new Thread(() => CheckForNewChunksAroundMultiplePoints(playerCameraPos, playerCameraForward, startRenDist, renIncrement));
                    checkDictionaryThread.Start();
                }

                if (checkForNewChunksDone)
                {
                    checkingForNewChunks = false;
                    checkForNewChunksDone = false;
                    ActivateAndDeactivateObjectsOnMainThread(); // turns generate and sort chunks on
                    manageChunksCounter = 0;

                    Debug.Log(currentlyRenderedChunks.Count);
                }
            }
        }
    }

I’m not sure what you’re doing that requires threading, but I’ll assume you’ve done that research correctly.

Over in the Unix world, starting a thread is considered a heavy task. Usually a thread is started and then given work to do via the same mechanism that you take the work out of the thread: some kind of delegate queue.

Have you tried just making a single Thread() at start and then feeding it work?

1 Like

No I haven’t! lol I will try that thank you.

1 Like

It works! Thank you so much! Another problem I have is I generate all the chunk data on another thread, but I need to draw the mesh on the main thread, so each chunk has a fixedUpdate that is there only to check if the initial generation thread is done and it can draw the mesh. So is there any way to either start a thread on the main thread FROM another thread? Or somehow cancel the fixedupdate during runtime? Because I only need it once upon creating the chunk. Should I just have the fixed update part in another script and just disable that component after it’s done?

I do most of my thread to thread communication using concurrent queues. They can take an instance of your own custom class of pretty much whatever you want. So you can use them to send instructions for another thread to do something (or stop doing something), send complex data, etc. So for this specific question, you can just have the main thread checking a concurrent queue for info coming from your own thread, and the data can tell the main thread to kick off another thread.

https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=net-5.0

1 Like