I did a bunch of test runs with different conversion combinations of Lists/Arrays as input with different types as output using different methods (CPU-single/parallel or GPU) and I thought I’d share the results.
The test was run with a compiled VS component (code attached far below). As input data I used a mesh M for traversing mesh.Vertices directly, and P (List<Point3d>) vertices from the deconstructed mesh.
The mesh had 404.006 vertices. Reading the Inputs was not included in the profiling times.

Below the results from processing the 404.006 mesh vertices with different methods & type combinations after manually re-running the component 5+ times to “warm up”. Notice the difference between single threaded (CPUs) and parallel (CPUp) versions of similar conversions.
404.006 vertices processed
01. CPUs (RC) mesh.Vertices.ToFloatArray() 9.3288 ms Inbuilt RhinoCommon
02. CPUs (RC) List<Point3d>.ToArray() 2.5 ms Inbuilt RhinoCommon
03. GPU float[]->double[] 8.8377 ms uses 01. (=9.33 + 8.84 ms)
04. CPUs float[]->double[] 2.3338 ms uses 01.
05. CPUp float[]->double[] 2.7228 ms uses 01.
06. GPU float[]->double[3][] 9.1549 ms uses 01.
07. CPUs List<Point3d>->double[3][] 3.2726 ms uses Input P (List)
08. CPUp List<Point3d>->double[3][] 2.157 ms uses Input P (List)
09. CPUs MeshVertextList->double[3][] 81.1281 ms uses Input M (Mesh)
10. CPUp MeshVertextList->double[3][] 16.0722 ms uses Input M (Mesh)
11. CPUs (revert) double[3][]->Point3d[] 2.8408 ms uses 10.
12. CPUp (revert) double[3][]->Point3d[] 2.071 ms uses 10.
13. CPUs (unsafe) Point3dArrayToDouble2DArray 2.895 ms uses 02.
14. CPUp (unsafe) Point3dArrayToDouble2DArray 2.0043 ms uses 02.
Fastest (once the data was read from the Inputs) was 08. (total 2.157 ms) processed by the CPU in parallel taking a List and converting it to a two dimensional double[3] array.
Other combinations required initial conversion to array for further processing, which added up execution times to unacceptable levels (which included the unsafe version).
// Rolf
Computer:

GPU: GTX970
The VS code being used. Notice that two methods (03. and 06.) uses Alea Gpu, but since they were not very efficient they can just be removed
protected override void SolveInstance(IGH_DataAccess DA)
{
RhinoApp.ClearCommandHistoryWindow();
Mesh mesh = null;
if (!DA.GetData(IN_Mesh, ref mesh))
return;
if (m_points == null)
m_points = new List<Point3d>();
m_points.Clear();
if (!DA.GetDataList(IN_Points, m_points))
return;
// ------------------------------------------------------------
watch.Start();
var vertices = mesh.Vertices.ToFloatArray();
watch.Stop(); RhinoApp.WriteLine("01. CPUs (RC) mesh.Vertices.ToFloatArray() {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
var point3dArray = m_points.ToArray();
watch.Stop(); RhinoApp.WriteLine("02. CPUs (RC) List<Point3d>.ToArray() {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
var double_array = GPU_FloatArrayToDoubleArray(vertices);
watch.Stop(); RhinoApp.WriteLine("03. GPU float[]->double[] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
double_array = new double[vertices.Length];
for (int i = 0; i < vertices.Length; i++) {
double_array[i] = (double)vertices[i];
}
watch.Stop(); RhinoApp.WriteLine("04. CPUs float[]->double[] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
double_array = new double[vertices.Length];
System.Threading.Tasks.Parallel.For(0, vertices.Length, i => {
double_array[i] = (double)vertices[i];
});
watch.Stop(); RhinoApp.WriteLine("05. CPUp float[]->double[] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
var vertex2DArray = GPU_FloatArrayToDouble2DArray(vertices);
watch.Stop(); RhinoApp.WriteLine("06. GPU float[]->double[3][] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
vertex2DArray = CPUs_Point3dListToDouble2DArray(m_points);
watch.Stop(); RhinoApp.WriteLine("07. CPUs List<Point3d>->double[3][] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
vertex2DArray = CPUp_Point3dListToDouble2DArray(m_points);
watch.Stop(); RhinoApp.WriteLine("08. CPUp List<Point3d>->double[3][] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
vertex2DArray = CPUs_VertextListToDouble2DArray(mesh.Vertices);
watch.Stop(); RhinoApp.WriteLine("09. CPUs MeshVertextList->double[3][] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
vertex2DArray = CPUp_VertextListToDouble2DArray(mesh.Vertices);
watch.Stop(); RhinoApp.WriteLine("10. CPUp MeshVertextList->double[3][] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
var revertedPoint3dArray = new Point3d[vertex2DArray[0].Length];
for (int i = 0; i < vertex2DArray[0].Length; i++) {
revertedPoint3dArray[i] = new Point3d(vertex2DArray[0][i], vertex2DArray[1][i], vertex2DArray[2][i]);
}
watch.Stop(); RhinoApp.WriteLine("11. CPUs (revert) double[3][]->Point3d[] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
revertedPoint3dArray = new Point3d[vertex2DArray[0].Length];
System.Threading.Tasks.Parallel.For(0, vertex2DArray[0].Length, i => {
revertedPoint3dArray[i] = new Point3d(vertex2DArray[0][i], vertex2DArray[1][i], vertex2DArray[2][i]);
});
watch.Stop(); RhinoApp.WriteLine("12. CPUp (revert) double[3][]->Point3d[] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ------------------------------------------------------------
watch.Restart();
var unsafe_points = CPUs_Point3dArrayToDouble2DArray(point3dArray);
watch.Stop(); RhinoApp.WriteLine("13. CPUs (unsafe) Point3dArrayToDouble2DArray {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
// ----------
// Recreate due to the above method freeing the array
point3dArray = m_points.ToArray();
// ------------------------------------------------------------
watch.Restart();
unsafe_points = CPUp_Point3dArrayToDouble2DArray(point3dArray);
watch.Stop(); RhinoApp.WriteLine("14. CPUp (unsafe) Point3dArrayToDouble2DArray {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
RhinoApp.WriteLine("----------------------------------");
// ------------------------------------------------------------
/*
watch.Restart();
DA.SetDataList(OUT_A, float_arr);
DA.SetDataList(OUT_B, unsafe_points);
watch.Stop(); RhinoApp.WriteLine("Output B = Point3d[] {0} ms", watch.Elapsed.TotalMilliseconds.ToString());
*/
// ==============================================================
}
private List<Point3d> m_points;
unsafe static double[][] CPUs_Point3dArrayToDouble2DArray(Point3d[] points)
{
// -------------------------------------
// using System.Runtime.InteropServices;
// -------------------------------------
var length = points.Length;
var double2DArray = new double[3][];
double2DArray[0] = new double[length];
double2DArray[1] = new double[length];
double2DArray[2] = new double[length];
var handle = GCHandle.Alloc(points, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
double* p = (double*)(ptr);
var stride = 3;
for (int i = 0; i < length; i++)
{
var j = i * stride;
double2DArray[0][i] = (double)p[j];
double2DArray[1][i] = (double)p[j + 1];
double2DArray[2][i] = (double)p[j + 2];
}
handle.Free();
return double2DArray;
}
unsafe static double[][] CPUp_Point3dArrayToDouble2DArray(Point3d[] points)
{
// -------------------------------------
// using System.Runtime.InteropServices;
// -------------------------------------
var length = points.Length;
var double2DArray = new double[3][];
double2DArray[0] = new double[length];
double2DArray[1] = new double[length];
double2DArray[2] = new double[length];
var handle = GCHandle.Alloc(points, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
double* p = (double*)(ptr);
var stride = 3;
System.Threading.Tasks.Parallel.For(0, length, i =>
{
var j = i * stride;
double2DArray[0][i] = (double)p[j];
double2DArray[1][i] = (double)p[j + 1];
double2DArray[2][i] = (double)p[j + 2];
});
handle.Free();
return double2DArray;
}
[GpuManaged]
public static double[] GPU_FloatArrayToDoubleArray(float[] vertices)
{
var gpu = Gpu.Default;
var vertices_dbl = new double[vertices.Length];
gpu.For(0, vertices.Length, i =>
{
vertices_dbl[i] = (double)vertices[i];
});
return vertices_dbl;
}
[GpuManaged]
public static double[][] GPU_FloatArrayToDouble2DArray(float[] vertices)
{
var stride_3 = 3;
var length = vertices.Length / stride_3;
var double2DArray = new double[3][];
double2DArray[0] = new double[length];
double2DArray[1] = new double[length];
double2DArray[2] = new double[length];
var gpu = Gpu.Default;
var lp = new LaunchParam(16, 256);
Action kernel = () =>
{
var start = blockIdx.x * blockDim.x + threadIdx.x;
var gpu_stride = gridDim.x * blockDim.x;
for (var i = start; i < length; i += gpu_stride)
{
var j = i * stride_3;
double2DArray[0][i] = (double)vertices[j];
double2DArray[1][i] = (double)vertices[j + 1];
double2DArray[2][i] = (double)vertices[j + 2];
}
};
gpu.Launch(kernel, lp);
return double2DArray;
}
public static double[][] CPUs_Point3dListToDouble2DArray(List<Point3d> points)
{
var length = points.Count;
var double2DArray = new double[3][];
double2DArray[0] = new double[length];
double2DArray[1] = new double[length];
double2DArray[2] = new double[length];
for (var i = 0; i < length; i++)
{
double2DArray[0][i] = (double)points[i].X;
double2DArray[1][i] = (double)points[i].Y;
double2DArray[2][i] = (double)points[i].Z;
}
return double2DArray;
}
public static double[][] CPUp_Point3dListToDouble2DArray(List<Point3d> points)
{
var length = points.Count;
var double2DArray = new double[3][];
double2DArray[0] = new double[length];
double2DArray[1] = new double[length];
double2DArray[2] = new double[length];
System.Threading.Tasks.Parallel.For(0, length, i =>
{
double2DArray[0][i] = (double)points[i].X;
double2DArray[1][i] = (double)points[i].Y;
double2DArray[2][i] = (double)points[i].Z;
});
return double2DArray;
}
public static double[][] CPUs_VertextListToDouble2DArray(Rhino.Geometry.Collections.MeshVertexList vertices)
{
var length = vertices.Count;
var double2DArray = new double[3][];
double2DArray[0] = new double[length];
double2DArray[1] = new double[length];
double2DArray[2] = new double[length];
for(var i=0; i<length; i++)
{
double2DArray[0][i] = (double)vertices[i].X;
double2DArray[1][i] = (double)vertices[i].Y;
double2DArray[2][i] = (double)vertices[i].Z;
}
return double2DArray;
}
public static double[][] CPUp_VertextListToDouble2DArray(Rhino.Geometry.Collections.MeshVertexList vertices)
{
var length = vertices.Count;
var double2DArray = new double[3][];
double2DArray[0] = new double[length];
double2DArray[1] = new double[length];
double2DArray[2] = new double[length];
System.Threading.Tasks.Parallel.For(0, length, i =>
{
double2DArray[0][i] = (double)vertices[i].X;
double2DArray[1][i] = (double)vertices[i].Y;
double2DArray[2][i] = (double)vertices[i].Z;
});
return double2DArray;
}