AutoCAD .NET API has three modes to open a DBObject or Entity, OpenMode.ForRead, OpenMode.ForWrite and OpenMode.ForNotify.
It is obvious that we have to open an object ForWrite when we need to change something inside it. Otherwise, disaster would just happen. However, it may not be so clear that what will happen if we open an object unnecessarily ForWrite. We are going to address this in this article. In terms of the ForNotify OpenMode, we leave it to future.
In general, it is not a big deal if you open an object in WRITE mode but for READ purposes in case the situation is not too complicated such as transactions are not nested too deep, the same object has not been opened too many times, and system resources are still sufficient. However, if performance is the most concern, we had better open an object in READ mode for READ purposes.
I know it sounds abstract and not so persuasive. Let us start with some nice, succinct and still complete example code to demonstrate the two cases and compare the behavior differences.
public static ObjectId GetLastCircle1()
{
ObjectId cirId = ObjectId.Null;
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
DBObject obj = tr.GetObject(id, OpenMode.ForRead);
if (obj is Circle)
cirId = obj.ObjectId;
}
tr.Commit();
}
return cirId;
}
public static ObjectId GetLastCircle2()
{
ObjectId cirId = ObjectId.Null;
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
foreach (ObjectId id in btr)
{
DBObject obj = tr.GetObject(id, OpenMode.ForWrite);
if (obj is Circle)
cirId = obj.ObjectId;
}
tr.Commit();
}
return cirId;
}
[CommandMethod("OpenReadForRead")]
public static void OpenReadForRead_Method()
{
Editor ed = AcadApplication.DocumentManager.MdiActiveDocument.Editor;
DateTime begin = DateTime.Now;
GetLastCircle1();
TimeSpan elapsed = DateTime.Now.Subtract(begin);
ed.WriteMessage("Time elapsed in OpenReadForRead: {0}\n", elapsed.TotalMilliseconds);
}
[CommandMethod("OpenWriteForRead")]
public static void OpenWriteForRead_Method()
{
Editor ed = AcadApplication.DocumentManager.MdiActiveDocument.Editor;
DateTime begin = DateTime.Now;
GetLastCircle2();
TimeSpan elapsed = DateTime.Now.Subtract(begin);
ed.WriteMessage("Time elapsed in OpenWriteForRead: {0}\n", elapsed.TotalMilliseconds);
}
Now we have two different approaches to do the same simple task, iterating through the model space of the working database and finding the last circle entity. One approach uses ForRead OpenMode for all operations including opening the BlockTable, the ModelSpace BlockTableRecord and each Entity inside it and the other uses ForWrite OpenModel for all these same reading operations.
We also have to commands to test the two methods respectively and print out time span that each consumes.
It is time to launch AutoCAD, create some circles, and run the two commands:
Command: CreateCircles1
Time elapsed in CreateCircles1: 374.4006
Command: CreateCircles2
Time elapsed in CreateCircles2: 639.6011
Command: OpenReadForRead
Time elapsed in OpenReadForRead: 374.4006
Command: OpenWriteForRead
Time elapsed in OpenWriteForRead: 889.2016
As can be seen, it took about one and half more time for the second command than the first one to finish the same work. So what overhead is it here?
Obviously, AutoCAD will do more things like undo filer maintaining behind the scene for the OpenMode.ForWrite than the OpenMode.ForRead even if no writing operations are performed at all in either case.
Therefore, the good practice is to Open Read for Read for sure. By the way, if we are only going to modify something in a particular record or symbol but not going to add/remove any new/existing entries to a BlockTableRecord, SysmbolTable or Dictionary, we do not have to open the container ForWrite. Opening it ForRead is sufficient and more efficient.
More coding tips will be created and demonstrated in the future. Please stay tuned.
The leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) provides various project wizards, item wizards, coders and widgets to help program AutoCAD .NET addins.
Posted by: |