In a comment to this blog post,
a developer had enquired about the possibility of using AccoreConsole to gather information from multiple drawings
without having to launch AccoreConsole for each drawing. AccoreConsole can only work on the drawing passed to it
using the “/i” startup switch. This prevents it from working on other drawings. But to considerably speed up the
processing, parallel aggregation can be used to launch multiple instances of AccoreConsole. This leverages the
multi-core capabilities of the system to perform and easily aggregate the results.
Here are two versions of a code that gathers the entity type of all the entities from drawings. In my Oct-core
system, the serial version completed its processing for 5 drawings in about 8 seconds, while the parallel version
completed it in 1.9 seconds. The results may vary at your end, but this should provide an idea of the performance
enhancement that can be expected.
Here is the code for the serial version :
// Serial version
Dictionary entityBreakUp = new Dictionary();
DirectoryInfo di = new DirectoryInfo(@"D:\Temp\TestDrawings");
FileInfo[] fiCollection = di.GetFiles("*.dwg");
DateTime startTime = DateTime.Now;
foreach (FileInfo fi in fiCollection)
{
string consoleOutput = string.Empty;
string entityNames = string.Empty;
using (Process coreprocess = new Process())
{
coreprocess.StartInfo.UseShellExecute = false;
coreprocess.StartInfo.CreateNoWindow = true;
coreprocess.StartInfo.RedirectStandardOutput = true;
coreprocess.StartInfo.FileName =
@"C:\Program Files\Autodesk\AutoCAD 2015\accoreconsole.exe";
coreprocess.StartInfo.Arguments =
string.Format("/i \"{0}\" /s \"{1}\" /l en-US",
fi.FullName,
@"C:\Temp\RunCustomNETCmd.scr");
coreprocess.Start();
// Max wait for 5 seconds
coreprocess.WaitForExit(5000);
StreamReader outputStream = coreprocess.StandardOutput;
consoleOutput = outputStream.ReadToEnd();
string cleaned =
consoleOutput.Replace(" ", string.Empty);
int first = cleaned.IndexOf("BreakupBegin")
+ "BreakupBegin".Length;
int last = cleaned.IndexOf("BreakupEnd");
if (first != -1 && last != -1)
entityNames =
cleaned.Substring(first, last - first);
outputStream.Close();
}
entityBreakUp.Add(fi.FullName, entityNames);
}
Console.WriteLine(string.Format(
"*** Serial processing : {0:0.0} seconds ***",
DateTime.Now.Subtract(startTime).TotalSeconds));
foreach (KeyValuePair kvp in entityBreakUp)
{
Console.WriteLine(string.Format("{0} - {1}",
kvp.Key.ToString(), kvp.Value.ToString()));
}
And here is the parallel version of the same code using Parallel.ForEach to launch multiple instances of
AccoreConsole.
// Parallel version
Dictionary entityBreakUp = new Dictionary();
DirectoryInfo di = new DirectoryInfo(@"D:\Temp\TestDrawings");
FileInfo[] fiCollection = di.GetFiles("*.dwg");
entityBreakUp.Clear();
// Assuming startTime is declared in a wider scope
startTime = DateTime.Now;
entityBreakUp = GetEntityBreakUp(fiCollection);
Console.WriteLine(string.Format(
"*** Parallel processing : {0:0.0} seconds ***",
DateTime.Now.Subtract(startTime).TotalSeconds));
foreach (KeyValuePair kvp in entityBreakUp)
{
Console.WriteLine(string.Format("{0} - {1}",
kvp.Key.ToString(), kvp.Value.ToString()));
}
// Launches multiple instance of AccoreConsole
static Dictionary GetEntityBreakUp(FileInfo[] fiCollection)
{
object lockObject = new object();
Dictionary entBreakup = new Dictionary();
Parallel.ForEach(
// The values to be aggregated
fiCollection,
// The local initial partial result
() => new Dictionary(),
// The loop body
(x, loopState, partialResult) =>
{
// Launch AccoreConsole and find the
// entity breakup
FileInfo fi = x as FileInfo;
string consoleOutput = string.Empty;
string entityBreakup = string.Empty;
using (Process coreprocess = new Process())
{
coreprocess.StartInfo.UseShellExecute = false;
coreprocess.StartInfo.CreateNoWindow = true;
coreprocess.StartInfo.RedirectStandardOutput = true;
coreprocess.StartInfo.FileName =
@"C:\Program Files\Autodesk\AutoCAD 2015\accoreconsole.exe";
coreprocess.StartInfo.Arguments =
string.Format("/i \"{0}\" /s \"{1}\" /l en-US",
fi.FullName,
@"C:\Temp\RunCustomNETCmd.scr");
coreprocess.Start();
// Max wait for 5 seconds
coreprocess.WaitForExit(5000);
StreamReader outputStream = coreprocess.StandardOutput;
consoleOutput = outputStream.ReadToEnd();
string cleaned =
consoleOutput.Replace(" ", string.Empty);
int first = cleaned.IndexOf("BreakupBegin")
+ "BreakupBegin".Length;
int last = cleaned.IndexOf("BreakupEnd");
if (first != -1 && last != -1)
entityBreakup =
cleaned.Substring(first, last - first);
outputStream.Close();
}
Dictionary partialDict = partialResult as Dictionary;
partialDict.Add(x.FullName, entityBreakup);
return partialDict;
},
// The final step of each local context
(partialEntBreakup) =>
{
// Enforce serial access to single, shared result
lock (lockObject)
{
Dictionary partialDict = partialEntBreakup as Dictionary;
foreach (KeyValuePair kvp in partialDict)
{
entBreakup.Add(kvp.Key, kvp.Value);
}
}
});
return entBreakup;
}
Here is the code from the custom .Net plugin for “EntBreakup” command which lists the entities in a drawing.
[CommandMethod("MyCommands",
"EntBreakup",
CommandFlags.Modal)]
public void EntBreakupMethod()
{
DocumentCollection docs = Autodesk.AutoCAD
.ApplicationServices.Core.Application.DocumentManager;
Document activeDoc = docs.MdiActiveDocument;
Editor ed = activeDoc.Editor;
// Obtain the selection set of all the entities
// in the drawing.
PromptSelectionResult psr1 = ed.SelectAll();
if (psr1.Status == PromptStatus.OK)
{
PrintSelectionSet("SelectAll", psr1.Value);
}
}
private void PrintSelectionSet(string title, SelectionSet ss)
{
DocumentCollection docs = Autodesk.AutoCAD
.ApplicationServices.Core.Application.DocumentManager;
Document activeDoc = docs.MdiActiveDocument;
Editor ed = activeDoc.Editor;
ed.WriteMessage(string.Format("{0}BreakupBegin",
Environment.NewLine));
foreach (ObjectId oid in ss.GetObjectIds())
{
ed.WriteMessage(string.Format("{0}{1}",
Environment.NewLine, oid.ObjectClass.Name));
}
ed.WriteMessage(string.Format("{0}BreakupEnd",
Environment.NewLine));
}
The sample project can be downloaded here :

Leave a Reply to MatthiasCancel reply