Message 1 of 3
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
@jeremytammik
Everyone knows that the application of transactions is available only in one thread, but what about reading the parameters of an element from several threads?
Reading the geometry of an object from several streams into a string works fine (and it gives a multiple increase in execution speed), but if you get at least a list of parameters, not to mention reading them,
// in 121-124 line
else
{
var param = elem.Parameters;
}
the revit simply closes even without an error report.
namespace Client.Main
{
[Transaction(TransactionMode.Manual)]
public class MultiThread : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Document Doc = commandData.Application.ActiveUIDocument.Document;
string data = "";
try
{
Stopwatch timer = new Stopwatch();
int threadCount = 5;
var list = new FilteredElementCollector(Doc).OfClass(typeof(Wall)).WhereElementIsNotElementType().ToList();
for (int i = 0; i < 10; i++)
{
list.AddRange(new FilteredElementCollector(Doc).OfClass(typeof(Wall)));
}
List<string> listResult = new List<string>();
timer.Start();
listResult = GetData(list);
timer.Stop();
data += $"Синхронно {timer.ElapsedMilliseconds}мс\t Count:{listResult.Count}\n";
if (DivideList(list, threadCount, out List<List<Element>> listOut))
{
timer.Reset();
timer.Start();
listResult = new List<string>();
List<Task<List<string>>> listTask = new List<Task<List<string>>>();
for (int i = 0; i < listOut.Count; i++)
{
var listCur = listOut[i];
var task = Task.Run(() => GetIdAsync(listCur));
listTask.Add(task);
}
Task.WaitAll(listTask.ToArray());
foreach (var task in listTask)
{
List<string> ids = task.Result;
listResult.AddRange(ids);
}
timer.Stop();
data += $"Многопоточно {timer.ElapsedMilliseconds}мс\t Count:{listResult.Count}\n";
timer.Reset();
timer.Start();
List<string>[] array = new List<string>[listOut.Count];
Parallel.For(0, listOut.Count, x =>
{
var listCur = listOut[x];
var dataParallel = GetData(listCur);
array[x] = dataParallel;
});
for (int i = 0; i < array.Length; i++)
{
listResult.AddRange(array[i]);
}
timer.Stop();
data += $"Параллельно {timer.ElapsedMilliseconds}мс\t Count:{listResult.Count}\n";
}
}
catch (Exception e)
{
data = e.Message;
}
TaskDialog.Show("Result", data);
return Result.Succeeded;
}
public static List<string> GetData(List<Element> listElem)
{
List<string> listData = new List<string>();
foreach (var elem in listElem)
{
if (true)
{
var geom = elem.get_Geometry(new Options()); //.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);
foreach (var geoElem in geom)
{
if (geoElem is Solid solid)
{
foreach (Face face in solid.Faces)
{
if (face is PlanarFace pFace)
{
Mesh mesh = pFace.Triangulate();
for (int i = 0; i < mesh.NumTriangles; i++)
{
var tri = mesh.get_Triangle(i);
XYZ a = tri.get_Vertex(0);
XYZ b = tri.get_Vertex(1);
XYZ c = tri.get_Vertex(2);
listData.Add($"{a.X:f4} {a.Y:f4} {a.Z:f4} {b.X:f4} {b.Y:f4} {b.Z:f4} {c.X:f4} {c.Y:f4} {c.Z:f4} ");
}
}
}
}
}
}
else
{
var param = elem.Parameters;
}
}
return listData;
}
public static async Task<List<string>> GetIdAsync(List<Element> listElem)
{
return GetData(listElem);
}
public static bool DivideList(List<Element> listElem, int coountList, out List<List<Element>> listOut)
{
listOut = null;
if (listElem == null || coountList <= 0 || listElem.Count < coountList)
{
return false;
}
int chunkSize = (int)Math.Ceiling((double)listElem.Count / coountList);
listOut = Enumerable.Range(0, coountList).Select(i => listElem.Skip(i * chunkSize).Take(chunkSize).ToList()).ToList();
return true;
}
}
}
If this is a known issue, can someone check if it is fixed in Revit 2025?
Solved! Go to Solution.