0

I've got a ConcurrentQueue<Vector3[]> that I'm filling up and I want to read out of it in chunks for the sake of performance.

private ConcurrentQueue<Vector3[]> positionsQueue = new ConcurrentQueue<Vector3[]>();

For example I want to wait until there's 20 Vector3[]s in queue and then read them as a single, continous array (I need the data to be simplified to a single Vector3[] as I'm passing it to a buffer later on). I am looking for a better method than looping, like a memory copy or sth similar. I tried using CopyTo() that copies queue contents into 2D array, but then I still need to convert 2D array to a merged 1D array.

Vector3[][] positionsFromQueue = new Vector3[positionsQueue.Count][];
positionsQueue.CopyTo(positionsFromQueue, 0);
Vector3[] mergedResult = ???

Tried using System.Buffer.BlockCopy, but I don't think I'm able to achieve what I want with that.

What else could I try to get a merged 1D vector and make this process' performance reasonable?

(btw I'm working in Unity, but asking this questions as a generic C# problem)

Shrimp
  • 514
  • 5
  • 9
  • _"...20 Vector3..."_ - sounds like premature optimisation to me? –  Jul 26 '22 at 09:16
  • I don't think you need to wait. If there are less than 20 just take all. If there are more than that, just take 20. – tia Jul 26 '22 at 09:40
  • Grouping those is a part of optimization further down the line. I'm grouping those in order to pass a bigger chunk of data at once to the renderer. I'm passing a lot of data to the GPU and need to find a middlepoint between doing it sequentially one by one (this is way too slow to work in real time) and passing most of the data at once (this introduces a certain load time). Hence chunks and grouping. And yeah, I'm not necessary waiting for those 20, I am taking all that are there with max of 20, that was simplification. – Shrimp Jul 26 '22 at 11:26
  • And as it's happening a lot of times during a single frame, I wanted to keep it as optimized as I can as well. Currently not sure if the chunks will hold 20 Vec3s or 2000. – Shrimp Jul 26 '22 at 11:56

1 Answers1

2

You should be able to use BlockCopy or Array.Copy, something like

var source = new Vector3[][];
var target = new Vector3[source.Sum(a => a.Length)];
var position = 0;
foreach(var chunk in source ){
    Buffer.BlockCopy(chunk, 0, target, position, target.Length);
    position += target.Length;
}

You should however read Array.Copy vs Buffer.BlockCopy, that suggest the difference is minimal, or even negative, compared to a plain loop for a short array. So I'm doubtful if you actually will gain much.

As with everything with performance I would recommend starting with profiling. That should reveal if this is really a problem at all. It is really easy to underestimate how fast computers are at some specific kinds of tasks.

If you really have a huge number of vectors I would probably not recommend using a concurrentQueue, and instead write your own specialized container for your specific use case. For example using double or triple buffering so you can switch buffers between the reader and writer.

If you really want to optimize you code you typically want to avoid any copying at all. So it is fairly common to work with fixed size buffers and using pointer + length or Span<T>/Memory<T> to refer to a region of memory.

JonasH
  • 28,608
  • 2
  • 10
  • 23