How to create a parallel for in Unity

Hello everyone.
I know that mono doesn’t support the System.Threading package but I would like to try to accellerate a texture creation by using something like:

Color[] dest, source;

// a lot of stuff...

void Update (){

   // some other stuff...
   
   Parallel.For (0, texture.height, y => {
      for (int x = 0; x < texture.width; x++) {
         int sourceIndex = (y * texture.width) + x;
         dest[sourceIndex].r = source[sourceIndex].r;
         dest[sourceIndex].g = source[sourceIndex].g;
         dest[sourceIndex].b = source[sourceIndex].b;
      }
   });

   // some other stuff...
}

Do you think is it possible to do this parallel execution in Unity?

Thanks :slight_smile:

Actually, though the general rule is that the Unity API is off-limits in separate threads, there are notable exceptions… And the Color class is one of them. It’s also perfectly legal to access the static methods in Mathf, or writing into the console using Debug.Log, even though those are actually members of the UnityEngine namespace.

Study, for example, this wiki post by Eric5h5 which uses the Color class in separate threads while scaling a texture. You can do that just fine because it operates on “off-line” objects, so to speak. The offending part about separate threads and Unity only pertains to things that directly affect the real-time renderstate. That is, instantiating GameObjects, changing the transform of something, replacing a material, etc.

In your case, it looks to me like you’re trying to parallelize the deep-copying of one texture’s colors into another array, right? You can do that concurrently pretty easily by just instantiating a thread per row in the original texture. You already have the algorithm for accessing rows when flattened to a 1D array, and you don’t even need to synchronize the threads’ access to the array, because they won’t be writing to the same area of the array as they handle one row each.

Make a method that takes object as parameter and start threads using ParameterizedThreadStart, passing the y variable as the parameter. In the method, cast the object back to an int, then use that to calculate the row of indices which are the write targets for that particular thread. Then, in the mainthread, loop over the height (the y’s) and start a thread for each. It will look something pretty close to this:

Color[] dest, source;

Texture2D texture;

private void StartThreads()
{
    for (int i = 0; i < texture.height; i++)
    {
        System.Threading.ParameterizedThreadStart pts = new System.Threading.ParameterizedThreadStart(ThreadedColorCopy);
        System.Threading.Thread workerForOneRow = new System.Threading.Thread(pts);
        workerForOneRow.Start(i);
    }
}

private void ThreadedColorCopy(object yVariable)
{
    int y = (int)yVariable;

    for (int x = 0; x < texture.width; x++)
    {
        int sourceIndex = (y * texture.width) + x;
        dest[sourceIndex].r = source[sourceIndex].r;
        dest[sourceIndex].g = source[sourceIndex].g;
        dest[sourceIndex].b = source[sourceIndex].b;
    }
}

(The above is untested but might work out of the box)

Caveat: It strikes me that one thread per row might be a little too aggressively multithreaded, as it would create 512 separate threads for a 512x512 texture. Instead, it might be an idea to give each thread a region of multiple rows, i.e. one thread handles rows 0-19, thread two handles rows 20-39, etc. You get the idea. It will make the code slightly more complicated, but probably more robust.

Ok guys this is my solution. You can also set how many threads you want to use. For me works like a charm !!! :wink:
Hope it can be good for anyone else:

public int threadsToUse = 5;

Color[] dest, source;
Texture2D texture;

int threadsStarted, threadsCompleted;
int pixelsPerThread, lostPixels;

// a lot of stuff...

void Start() {

   // lots of other stuff...

   pixelsPerThread = texture.height / threadsToUse;
   lostPixels = texture.height % threadsToUse;
}

void Update() {
   if (threadsStarted == 0) {

      // some other stuff...

      threadsCompleted = 0;
      for (int i = 0; i < threadsToUse; i++) {			
         ParameterizedThreadStart pts = new ParameterizedThreadStart(ThreadedColorCopy);
         Thread workerForOneRow = new System.Threading.Thread(pts);
         workerForOneRow.Start(i);
         threadsStarted++;
      }
   }
   else if (threadsCompleted == threadsToUse) {			
      threadsStarted = 0;
      texture.SetPixels(dest);
      texture.Apply();
   }
}

private void ThreadedColorCopy(object threadParamsVar) {
   int i = (int)threadParamsVar;
   int fromY = i * (pixelsPerThread);
   int toY = ((i + 1) * pixelsPerThread) - 1;

   if (i == threadsToUse - 1) {
      toY += lostPixels;
   }

   Debug.Log("Thread " + threadParams.threadId + " - from " + fromY + " to " + toY);

   for (int y = fromY; y <= toY; y++) {
      for (int x = textureWidth - 1; x >= 0; x--) {
         int sourceIndex = (y * texture.width) + x;
         dest[sourceIndex].r = source[sourceIndex].r;
         dest[sourceIndex].g = source[sourceIndex].g;
         dest[sourceIndex].b = source[sourceIndex].b;
      }
   }
   threadsCompleted++;
}

:slight_smile:

I dont have 100% sure, but I think that you can.

You can not access any unity3d stuff outside of main thread because unity is not thread safe, but you are free to use many threads do you like.

You can read some data in unity main thread, move it to a indenpendent type like byte, instantiate a new thread to process the bytes, when it finished, you use the main thread to read the byte and update your data.

The project AStarpathfind do some stuff like that.

http://www.arongranberg.com/astar/docs/index.php

Have a look here : https://forum.unity3d.com/threads/c-optimized-and-advanced-classic-threads-for-unity-option-with-setthreadaffinitymask.463307/