Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Алексей (IdeaSoft) от 25-01-2016, 23:25:50

Название: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 25-01-2016, 23:25:50
Скажите, замерял ли кто когда скорость работы функции чтения данных из XRecord
                             Данные железа:  ЦП Core i5, 4X1,9 ГГц,   ОЗУ 6Г Win 8.1 64bit
                                             Софт: AutoCAd 2012
объем чтения из записи XRecord: 7Кбайт
                                время чтения: 8 мс
На первый взгляд быстро, но когда нужно прочесть 1000 таких записей получается, что пользователь должен ждать уже 8 сек.
Скорее должно помочь, если снизить объем записи Xrecord. 7К очень уж много я там храню лишней информации.
 Или оператор  Try.. Catch тормозов добавляет.

Вот код функции для анализа:

Код - vb.net [Выбрать]
  1.  
  2.     Public Shared Function acadnet_xrecord_Get_String(ByVal dictName As String, _
  3.                                                       ByVal keyRec As String, _
  4.                                                       ByVal doc As CAD_APS.Document, _
  5.                                                       ByVal db As CAD_DBS.Database) As String
  6.  
  7.         Dim retS As String = vbNullString
  8.         Using doc.LockDocument
  9.             Using tr As CAD_DBS.Transaction = db.TransactionManager.StartTransaction
  10.                 Dim dicts As CAD_DBS.DBDictionary = tr.GetObject(db.NamedObjectsDictionaryId, CAD_DBS.OpenMode.ForRead, False)
  11.                 If dicts.Contains(dictName) Then
  12.                     Dim CurrDict As CAD_DBS.DBDictionary = tr.GetObject(dicts.GetAt(dictName), CAD_DBS.OpenMode.ForRead, False)
  13.                     If CurrDict.Contains(keyRec) Then
  14.                         Try
  15.                             Dim xrec As CAD_DBS.Xrecord = tr.GetObject(CurrDict.GetAt(keyRec), CAD_DBS.OpenMode.ForRead, False)
  16.                             retS = xrec.Data.AsArray(0).Value.ToString
  17.                         Catch ex As System.Exception
  18.                         End Try
  19.                     End If
  20.                 End If
  21.             End Using
  22.         End Using
  23.         Return retS
  24.     End Function
  25.  
  26.  



Название: Re: Замер скорости чтения XRecord
Отправлено: Андрей Бушман от 25-01-2016, 23:29:15
Или оператор  Try.. Catch тормозов добавляет.
Этот тынц (https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/database/compare) наглядно демонстрирует, что наличие исключений в цикле может существенно влиять на скорость работы приложения.
Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 25-01-2016, 23:32:31
Этот тынц наглядно демонстрирует, что наличие исключений в цикле может существенно влиять на скорость работы приложения.
Убрал из алгоритма оператор Try.. Catch - все равно 8 мс читает.
Название: Re: Замер скорости чтения XRecord
Отправлено: Андрей Бушман от 25-01-2016, 23:40:46
Убрал из алгоритма оператор Try.. Catch - все равно 8 мс читает.
На скорость влияет не "Try.. Catch", а возникающие исключения (Exceptions). Если твой код работал без "Try.. Catch", значит исключений не возникало. Я не вижу в твоём коде явного способа закрытия транзакции. Соответственно выполняется Commit, что является достаточно ресурсоёмким и, в данном случае, совершенно не нужным.

Если метод планируется использовать в больших циклах, то возможно имеет смысл передавать объект Transaction дополнительным параметром, а не создавать его каждый раз заново.

Ты не проверяешь в своём коде ни параметры на входе, ни результаты, отправляемые на выход. Это плохой подход в программировании.
Название: Re: Замер скорости чтения XRecord
Отправлено: Александр Ривилис от 25-01-2016, 23:47:37
7К очень уж много я там храню лишней информации.
Похоже, что да.

Или оператор  Try.. Catch тормозов добавляет.
Только если исключение реально возникает.
В твоём коде нет tr.Commit - соотвественно происходит откат транзакции, а это дополнительное время, часто очень значительное.
Я бы в этом коде обошелся бы совсем без транзакции.

Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 25-01-2016, 23:55:57
Ты не проверяешь в своём коде ни параметры на входе, ни результаты
Параметры на входе Doc as Document и db As DataBase я проверяю снаружи функции
параметр на выходы retS тоже проверяю вне функции
Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 25-01-2016, 23:57:13
Я бы в этом коде обошелся бы совсем без транзакции
Вот вот! Я тоже думаю к чему мне транзакция,
если базу открываю для чтения с флагом OpenMode.ForRead
Название: Re: Замер скорости чтения XRecord
Отправлено: Андрей Бушман от 25-01-2016, 23:57:26
Параметры на входе Doc as Document и db As DataBase я проверяю снаружи функции
параметр на выходы retS тоже проверяю вне функции
Плохой, подверженный ошибкам подход.
Название: Re: Замер скорости чтения XRecord
Отправлено: Андрей Бушман от 25-01-2016, 23:58:11
Вот вот! Я тоже думаю к чему мне транзакция,
если базу открываю для чтения с флагом OpenMode.ForRead
Кто-то мешает переписать код без использования транзакции? Можешь заменить на эмуляцию (http://bushman-andrey.blogspot.ru/2014/09/blog-post.html), в этом случае придётся заменить в коде только одно слово.
Название: Re: Замер скорости чтения XRecord
Отправлено: Александр Ривилис от 26-01-2016, 00:01:41
Я не вижу в твоём коде явного способа закрытия транзакции. Соответственно выполняется Commit, что является достаточно ресурсоёмким и, в данном случае, совершенно не нужным.
Если нет Commit, то выполняется Abort, который действительно ресурсоемкий.
P.S.: Я понимаю, что это у тебя просто описка, но уточнить я должен дабы не вводить никого в заблуждение.
Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 26-01-2016, 00:02:57
Плохой, подверженный ошибкам подход.
А что Doc и db вернее нужно было бы проверять в теле функции!?
 
Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 26-01-2016, 00:04:26
Если нет Commit, то выполняется Abort, который действительно ресурсоемкий.
Да-Да!! Саша ты прав поставил Commit и вместо 8 мс функция сразу начала работать 1 мс, а то и меньше < 1
Нужно попробовать вообще без транзакции сделать.
Название: Re: Замер скорости чтения XRecord
Отправлено: Андрей Бушман от 26-01-2016, 00:07:35
Плохой, подверженный ошибкам подход.
А что Doc и db вернее нужно было бы проверять в теле функции!?
А что, разве это не очевидно? Текущая реализация вынуждает писать тебя код проверки каждый раз, как ты будешь использовать эту функцию. Чем больше кода, тем больше вероятность появления ошибки. Кроме того, в каких-то фрагментах ты можешь вовсе забыть выполнить эту проверку. То же самое относится и к случаям, когда твою функцию будут использовать др. программисты или программы - им каждый раз нужно будет писать код проверки. Текущая реализация функции предполагает, что программист, использующий её, должен быть знаком и с её реализацией (т.е. должен знать о том, что ему нужно дополнительно выполнять ряд проверок). Это плохой, подверженный ошибкам подход в программировании.
Название: Re: Замер скорости чтения XRecord
Отправлено: Андрей Бушман от 26-01-2016, 00:09:04
Если нет Commit, то выполняется Abort, который действительно ресурсоемкий.
Согласен. Под вечер уже плохо соображаю. :)
Название: Re: Замер скорости чтения XRecord
Отправлено: Андрей Бушман от 26-01-2016, 00:10:46
Нужно попробовать вообще без транзакции сделать.
Чем не устроил вариант с эмуляцией? По сути - это способ "без транзакции", который в коде выглядит "как транзакция".
Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 26-01-2016, 00:13:57
А что, разве это не очевидно? Текущая реализация вынуждает писать тебя код проверки каждый раз, как ты будешь использовать эту функцию. Чем больше кода, тем больше вероятность появления ошибки. Кроме того, в каких-то фрагментах ты можешь вовсе забыть выполнить эту проверку. То же самое относится и к случаям, когда твою функцию будут использовать др. программисты или программы - им каждый раз нужно будет писать код проверки. Текущая реализация функции предполагает, что программист, использующий её, должен быть знаком и с её реализацией (т.е. должен знать о том, что ему нужно дополнительно выполнять ряд проверок). Это плохой, подверженный ошибкам подход в программировании

Да ты прав поставлю в тело функции. Проверка входных параметров вроде время так много не отнимает. Хотя и вызываю во всем проекте эту функцию 6 раз. Все же подход к грамотному программированию должен быть.
Спасибо ребята вы мне помогли!
Ярослав с Наташей на дне разработчика 21 января 2016 хвалили наш форум. Много пришло новых людей. В этом году 200 чел пришли на DevDay
Лично я рад что есть этот форум.
Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 26-01-2016, 00:14:21
А что, разве это не очевидно? Текущая реализация вынуждает писать тебя код проверки каждый раз, как ты будешь использовать эту функцию. Чем больше кода, тем больше вероятность появления ошибки. Кроме того, в каких-то фрагментах ты можешь вовсе забыть выполнить эту проверку. То же самое относится и к случаям, когда твою функцию будут использовать др. программисты или программы - им каждый раз нужно будет писать код проверки. Текущая реализация функции предполагает, что программист, использующий её, должен быть знаком и с её реализацией (т.е. должен знать о том, что ему нужно дополнительно выполнять ряд проверок). Это плохой, подверженный ошибкам подход в программировании

Да ты прав поставлю в тело функции проверки. Проверка входных параметров вроде время так много не отнимает. Хотя и вызываю во всем проекте эту функцию 6 раз. Все же подход к грамотному программированию должен быть.
Спасибо ребята вы мне помогли!
Ярослав с Наташей на дне разработчика 21 января 2016 хвалили наш форум. Много пришло новых людей. В этом году 200 чел пришли на DevDay
Лично я рад что есть этот форум.
Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 26-01-2016, 00:16:34
Чем не устроил вариант с эмуляцией?
Ну вот я и попробую с этой эмуляцией и посмотрю может еще быстрее работать будет.
Название: Re: Замер скорости чтения XRecord
Отправлено: Андрей Бушман от 26-01-2016, 00:21:56
Ярослав с Наташей на дне разработчика 21 января 2016 хвалили наш форум.
Я на форуме до тех пор, пока здесь работает А.Н. Ривилис и отвечает на мои вопросы. :) Если ситуация изменится, то форум станет мне не интересным (как это уже случилось с caduser.ru и dwg.ru) и я перестану его посещать. Без А.Н. рейтинг форума резко упадёт, так что дружно ратуем за то, чтобы Автодеск и впредь продолжал оплачивать работу А.Н. Ривилиса на данном ресурсе.
Название: Re: Замер скорости чтения XRecord
Отправлено: Дмитрий Загорулькин от 26-01-2016, 00:47:10
У меня такой метод живет в библиотеке:
Код - C# [Выбрать]
  1.         /// <summary>
  2.         /// Получение данных из корневого словаря расширения объекта
  3.         /// </summary>
  4.         /// <param name="obj">Объект</param>
  5.         /// <param name="dataName">Название данных</param>
  6.         /// <returns>
  7.         /// Данные в виде объекта ResultBuffer или null при неудаче
  8.         /// </returns>
  9.         public static ResultBuffer ReadRootData(DBObject obj, string dataName)
  10.         {
  11.             ObjectId dbExtDictId = obj.ExtensionDictionary;
  12.             if (dbExtDictId.Verify())
  13.             {
  14. #pragma warning disable 618
  15.                 using (DBDictionary dbExtDict
  16.                     = dbExtDictId.Open(OpenMode.ForRead, false) as DBDictionary)
  17. #pragma warning restore 618
  18.                 {
  19.                     if (dbExtDict != null && dbExtDict.Contains(dataName))
  20.                     {
  21.                         ObjectId xRecId = dbExtDict.GetAt(dataName);
  22. #pragma warning disable 618
  23.                         using (Xrecord xRec = xRecId.Open
  24.                             (OpenMode.ForRead, false) as Xrecord)
  25. #pragma warning restore 618
  26.                         {
  27.                             if (xRec != null)
  28.                             {
  29.                                 return xRec.Data;
  30.                             }
  31.                         }
  32.                     }
  33.                 }
  34.             }
  35.             return null;
  36.         }
  37.  
  38.         public static bool Verify(this ObjectId id)
  39.         {
  40.             return
  41.                 !id.IsNull &&
  42.                 id.IsValid &&
  43.                 !id.IsErased &&
  44.                 !id.IsEffectivelyErased;
  45.         }
  46.  
  47.  
Это как пример, как без транзакции читать словарь. Тут ExtensionDictionary, а не NOD. Но принцип тот же.
Название: Re: Замер скорости чтения XRecord
Отправлено: Алексей (IdeaSoft) от 26-01-2016, 01:32:37
Это как пример, как без транзакции читать словарь[/quo
Спасибо испробую этот метод!
 
Название: Re: Замер скорости чтения XRecord
Отправлено: Привалов Дмитрий от 26-01-2016, 08:30:25
На первый взгляд быстро, но когда нужно прочесть 1000 таких записей получается, что пользователь должен ждать уже 8 сек.
Ключевое слово здесь (когда нужно прочесть 1000 таких записей). Когда есть циклы, особенно вложенные смотри в первую очередь  на циклы!

Твоя функция создана универсальной для чтения одиночной записи , а не 1000 записей подряд.
скорее всего незачем вызывать 1000 раз подряд:
- блокировку документа,
- открытие закрытие транзакции
- получение NamedObjectsDictionary
это и нужно оптимизировать в первую очередь.

Не знаю до конца твоей задачи,  сколько database, DBDictionary и Xrecord. Откуда беруться database. Для одной database примерно так.
Код - C# [Выбрать]
  1. private void ReadAllData()
  2. {
  3.             Document document = Cad.DocumentManager.MdiActiveDocument;
  4.             DocumentLock documentLock = document.LockDocument();
  5.             Database db = HostApplicationServices.WorkingDatabase;
  6.             Transaction tr = database.TransactionManager.StartTransaction();
  7.             DBDictionary namedObjectsDictionary = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead, false);
  8.             foreach (string dictName in dictNameArray)
  9.             {
  10.                if (namedObjectsDictionary.Contains(dictName))
  11.                {
  12.                   DBDictionary CurrDict = (DBDictionary)tr.GetObject(namedObjectsDictionary.GetAt(dictName), OpenMode.ForRead, false);
  13.                   foreach (string keyRec in keyNameArray)
  14.                   {
  15.                      string retS = acadnet_xrecord_Get_String(dictName, keyRec, tr, CurrDict);
  16.                   }
  17.                }
  18.                
  19.             }
  20.             transaction.Commit();
  21.             transaction.Dispose();
  22.             documentLock.Dispose();
  23. }
  24.  
  25. private string acadnet_xrecord_Get_String(string dictName, string keyRec, Transaction tr, DBDictionary CurrDict)
  26. {
  27.             string retS = "";
  28.             if (CurrDict.Contains(keyRec))
  29.             {
  30.                Xrecord xrec = (Xrecord)tr.GetObject(CurrDict.GetAt(keyRec), OpenMode.ForRead, false);
  31.                retS = xrec.Data.AsArray()[0].Value.ToString();
  32.             }
  33.             return retS;        
  34. }


using Transaction, проверки try  или !=null допилить не долго ;-)