Author Topic: ObjectId.GetObject vs Transaction.GetObject  (Read 4303 times)

0 Members and 1 Guest are viewing this topic.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
ObjectId.GetObject vs Transaction.GetObject
« on: April 03, 2010, 03:45:56 AM »
Hi,

Playing with some C# code here, I noticed the 'ObjectId.GetObject' statement runs faster than the 'Transaction.GetObject' one.

Example, I have to convert DBPoint ObjectId array (ids) into a Point3d array (pts), within a transaction (tr), doing:
Code: [Select]
Point3d[] pts = Array.ConvertAll<ObjectId, Point3d>(
    isd, x => ((DBPoint)x.GetObject(OpenMode.ForRead)).Position);
runs 2 times faster than:
Code: [Select]
Point3d[] pts = Array.ConvertAll<ObjectId, Point3d>(
    isd, x => ((DBPoint)tr.GetObject(x, OpenMode.ForRead)).Position);

But is it as safe ?
The help says ObjectId.GetObject calls the TransactionManager.GetObject() method of the top transaction.
As far as I understand, objects which are opened with Transaction.GetObject are closed and disposed at the end of the transaction.
Is it the same for objects opened through ObjectId.GetObject or do they need to be explicitly disposed ?
Speaking English as a French Frog

Jeff H

  • Needs a day job
  • Posts: 6150
Re: ObjectId.GetObject vs Transaction.GetObject
« Reply #1 on: March 03, 2011, 05:27:54 AM »
But is it as safe ?
The help says ObjectId.GetObject calls the TransactionManager.GetObject() method of the top transaction.
As far as I understand, objects which are opened with Transaction.GetObject are closed and disposed at the end of the transaction.
Is it the same for objects opened through ObjectId.GetObject or do they need to be explicitly disposed ?
I have never had a problem with it.

The way I understand is.

If by top transaction you mean transaction on top of the stack as transaction manager keep them in a stack, I would not see a difference. Since that is the most recent Transaction.
If it associates it with the outermost transaction I could see that maybe speeding up things. Since when a transaction is successfully committed all the objects "bubble up" to the containing transaction. That's why all changes in inner transactions do not take affect unless all transactions that it is contained are committed or until the last transaction popped off the stack is committed.

I have always wondered about that also.

dan.glassman

  • Guest
Re: ObjectId.GetObject vs Transaction.GetObject
« Reply #2 on: March 03, 2011, 02:07:10 PM »
I don't see that behavior (performance difference) in this concocted test, which may be flawed...and I've never pseudo-profiled .net code.  In fact, my test has the relative speeds going the other way.

Reflector indicates that they all end up using TransactionManager.GetObjectInternal() to do the work; should be quite safe*.

*Despite my first post on these forums, where I mistakenly thought ObjectId.GetObject was transaction-less -- silly n00b.  :D.

Code: [Select]
[CommandMethod("openspeeds")]
public void TestOpenSpeeds()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    PromptEntityResult per = ed.GetEntity("gimmeh ent: ");
    ObjectId id = per.ObjectId;

    ed.WriteMessage("\nStopwatch frequency is {0}MHz\n", Stopwatch.Frequency/1000000);
    ed.WriteMessage("Stopwatch is {0}high resolution, fwiw\n", Stopwatch.IsHighResolution? "": "not ");

    ed.WriteMessage("\nWithout transaction: {0}ms\n", NoTrans(id));
    ed.WriteMessage("With transaction, ObjectId.GetObject: {0}ms\n", TransUseObjectId(id));
    ed.WriteMessage("With transaction, Transaction.GetObject: {0}ms\n", TransUseTrans(id));
    ed.WriteMessage("With transaction, TransactionManager.GetObject: {0}ms\n", TransUseTransMan(id));            
}

private double NoTrans(ObjectId id)
{
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < 100000; ++i)
    {
        DBObject obj = id.Open(OpenMode.ForRead);
        obj.Close();                
    }
    sw.Stop();
    return sw.Elapsed.TotalMilliseconds;
}

private double TransUseObjectId(ObjectId id)
{
    Stopwatch sw = Stopwatch.StartNew();
    using (Transaction t = id.Database.TransactionManager.StartTransaction())
    {                
        for (int i = 0; i < 100000; ++i)
        {
            DBObject obj = id.GetObject(OpenMode.ForRead);
        }                
        t.Commit();            
    }
    sw.Stop();
    return sw.Elapsed.TotalMilliseconds;
}

private double TransUseTrans(ObjectId id)
{
    Stopwatch sw = Stopwatch.StartNew();
    using (Transaction t = id.Database.TransactionManager.StartTransaction())
    {                
        for (int i = 0; i < 100000; ++i)
        {
            DBObject obj = t.GetObject(id, OpenMode.ForRead);
        }                
        t.Commit();
    }
    sw.Stop();
    return sw.Elapsed.TotalMilliseconds;
}

private double TransUseTransMan(ObjectId id)
{
    Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = id.Database.TransactionManager;
    Stopwatch sw = Stopwatch.StartNew();
    using (Transaction t = id.Database.TransactionManager.StartTransaction())
    {
        
        for (int i = 0; i < 100000; ++i)
        {
            DBObject obj = tm.GetObject(id, OpenMode.ForRead);
        }                
        t.Commit();
    }
    sw.Stop();
    return sw.Elapsed.TotalMilliseconds;
}

for which i get

Code: [Select]
Command: openspeeds gimmeh ent:
Stopwatch frequency is 3MHz
Stopwatch is high resolution, fwiw

Without transaction: 166.7821ms
With transaction, ObjectId.GetObject: 320.3773ms
With transaction, Transaction.GetObject: 124.9978ms
With transaction, TransactionManager.GetObject: 113.6256ms
« Last Edit: March 03, 2011, 02:21:06 PM by dan.glassman »

dan.glassman

  • Guest
Re: ObjectId.GetObject vs Transaction.GetObject
« Reply #3 on: March 03, 2011, 02:36:48 PM »
Example more inline with OP's function.  I see Transaction.GetObject being 2x faster than ObjectId.GetObject.

Code: [Select]
[CommandMethod("pointses")]
public void PreciousPointses()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;

    ObjectIdCollection pointIds = new ObjectIdCollection();
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
        BlockTableRecord curspace =
            t.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
        for (int i = 0; i < 10000; ++i)
        {
            DBPoint pObj = new DBPoint(Point3d.Origin);
            pointIds.Add(curspace.AppendEntity(pObj));
            t.AddNewlyCreatedDBObject(pObj, true);
        }
        t.Commit();
    }

    Point3dCollection p3dc = new Point3dCollection();
   
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
        Stopwatch sw = Stopwatch.StartNew();
        foreach (ObjectId pointId in pointIds)
        {
            p3dc.Add(((DBPoint)(t.GetObject(pointId, OpenMode.ForRead))).Position);
        }
        sw.Stop();
        t.Commit();
        doc.Editor.WriteMessage("\nTransaction.GetObject: {0}ms\n", sw.Elapsed.TotalMilliseconds);
    }

    p3dc.Clear();
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
        Stopwatch sw = Stopwatch.StartNew();
        foreach (ObjectId pointId in pointIds)
        {
            p3dc.Add(((DBPoint)(pointId.GetObject(OpenMode.ForRead))).Position);
        }
        sw.Stop();
        t.Commit();
        doc.Editor.WriteMessage("ObjectId.GetObject: {0}ms\n", sw.Elapsed.TotalMilliseconds);
    }   
}

For which I get:

Code: [Select]
Transaction.GetObject: 19.7501ms
ObjectId.GetObject: 49.1398ms

Jeff H

  • Needs a day job
  • Posts: 6150
Re: ObjectId.GetObject vs Transaction.GetObject
« Reply #4 on: March 04, 2011, 05:27:01 AM »
What about using 2 transactions with 2 seperate databases?

That could possibly cause a issue to creep up?

Just thinking need to look at some code or code up one to see.

Might not be a issue at all.