What I compared here was not from the code above it was the total execution time of SetData being called 100,000 times from a component receiving a list of n items and calling SetData on n items. The reason i compared this to SetData being called 100,000 times in the same component was that i didn’t want to compare apples to apples as this is not a real use case. It took 55ms for a component which receives a single item to call SetData on that single items with 100,000 items compared to 5.5s for the SetDataList to be called with 100,000 objects so both were timed for n=100,000.
In terms of using GH_Structure I have tried this and I am surprised at how much more performant this is. We are now within the realm that i expected the operation to perform. Time to create a DataTree with 100,000 was 58ms in this example and 17ms to set the DataTree, this is an enormous difference from the SetDataList which took 13.3s. I have also added the iteration of SetData in this example @TomTom, i do see this is a real use case but is here for the apples to apples comparison, and it took the same time as SetDataList.
(I’ve had to reduce the number to 50,000 for some reason with the screen recording active 100,000 items could take 20s+)

What surprises me is the right most component processes 50,000 inputs in 20ms. It seems like the solution is to avoid SetDataList and handle the creation of the GH_DataStructure yourself. The GH_DataStructure does require the generic to implement IGH_Goo, without looking into the details i figured using GH_ObjectWrapper would be a quick approach.
What’s unclear to me is what to use when working with a list of list of objects, am i really expected to loop through the nested list wrapping all my objects in a GH_ObjectWrapper, or can i wrap the high level list and wrap the nested list in another type which can be understood by grasshopper.
A screen shot too:
Also code too:
protected override void SolveInstance(IGH_DataAccess DA)
{
int count = default;
DA.GetData(0, ref count);
var stopWatchCreateData = new Stopwatch();
var stopWatchSetData = new Stopwatch();
var stopWatchSetDataList = new Stopwatch();
var stopWatchCreateStructure = new Stopwatch();
var stopWatchNewWrapperObj = new Stopwatch();
var stopWatchSetDataTree = new Stopwatch();
var genericObject = new object();
stopWatchCreateData.Start();
var genericList = new List<object>();
for (int i = 0; i < count; i++)
{
genericList.Add(new object());
}
stopWatchCreateData.Stop();
stopWatchSetData.Restart();
for (int i = 0; i < count; i++)
{
DA.SetData(0, genericObject);
}
stopWatchSetData.Stop();
stopWatchSetDataList.Start();
DA.SetDataList(1, genericList);
stopWatchSetDataList.Stop();
var objwrapperStopWatch = new Stopwatch();
stopWatchCreateStructure.Start();
var structure = new GH_Structure<GH_ObjectWrapper>();
foreach (var item in genericList)
{
stopWatchNewWrapperObj.Start();
var objwrap = new GH_ObjectWrapper(genericList);
stopWatchNewWrapperObj.Stop();
structure.Append(objwrap);
}
stopWatchCreateStructure.Stop();
stopWatchSetDataTree.Start();
DA.SetDataTree(2, structure);
stopWatchSetDataTree.Stop();
DA.SetData(3, stopWatchCreateData.ElapsedMilliseconds);
DA.SetData(4, stopWatchCreateStructure.ElapsedMilliseconds);
DA.SetData(5, objwrapperStopWatch.ElapsedMilliseconds);
DA.SetData(6, stopWatchSetData.ElapsedMilliseconds);
DA.SetData(7, stopWatchSetDataList.ElapsedMilliseconds);
DA.SetData(8, stopWatchSetDataTree.ElapsedMilliseconds);
}