Можно ли ускорить срабатывание ReadDwgFile? Или есть другие альтернативы?

Автор Тема: Можно ли ускорить срабатывание ReadDwgFile? Или есть другие альтернативы?  (Прочитано 8428 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Всем доброго. Столкнулся с проблемой, которую вообще не ожидал встретить.
Суть задачи - необходимо открыть сторонний dwg. Использовал стандартный ReadDwgFile - и оно по скорости почему-то уступает (по крайней мере в моих условиях) использовавшемуся в лиспе ObjectDBX.
Простое открытие 19 файлов, весом от 1 до 2 метров каждый под NET кушает 2 минуты. ObjectDBX в некомпилированном (!) лиспе с теми же задачами справляется за максимум 15 секунд.
Открываю кодом типа
Код - C# [Выбрать]
  1. public void TryToOpenFile(string FileName)
  2. {
  3.     Database _fileDb = new Database(false, true);
  4.     try
  5.     {
  6.         _fileDb.ReadDwgFile(FileName, FileShare.ReadWrite, false, "");
  7.     }
  8.     catch
  9.     {
  10.         // На случай, если файл находится в режиме ReadOnly
  11.         string _copyName = Path.Combine(Path.GetTempPath(), Path.GetFileName(FileName));
  12.         File.Copy(FileName, _copyName, true);
  13.         _fileDb.ReadDwgFile(_copyName, FileShare.ReadWrite, false, "");
  14.     }
  15. }
И на ReadDwgFile невероятные потери времени! Что я делаю не так?
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн doctorRAZ

  • ADN OPEN
  • Сообщений: 42
  • Карма: 0
  • Skype: doctorraz
на ReadDwgFile невероятные потери времени!
возможно есть смысл обернуть в Using, тем более в цикле гоняешь
Код - C# [Выбрать]
  1.    using (Db.Database db0 = new Db.Database(false, false))
  2.           {
  3.                   db0.ReadDwgFile(sFilPathPrefix, Db.FileOpenMode.OpenForReadAndAllShare, false, "", false);
  4.                    Db.HostApplicationServices.WorkingDatabase = db0;
  5.  
  6.            }
  7.  

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Класс реализовывает IDisposable. Я полагал, что этого достаточно.
Как бы то ни было - именно на ReadDwgFile потери времени вообще невероятные. Я явно что-то делаю не так. Но что?
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн doctorRAZ

  • ADN OPEN
  • Сообщений: 42
  • Карма: 0
  • Skype: doctorraz
Цитировать
Найдено форматов 1 в 30 файлах за 00:00:08.8418864
30 файлов ~5Мб каждый, перебор всех примитивов во всех пространствах и это не AutoCAD (в AutoCAD еще быстрее перебирает)
возможно время чтения зависит от того, что в файле..

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Хорошо, поставлю вопрос по-другому :) Почему ObjectDBX срабатывает в разы быстрее на тех же файлах?
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis

Хорошо, поставлю вопрос по-другому  Почему ObjectDBX срабатывает в разы быстрее на тех же файлах?
Очень странно. У меня нет никаких сооражений на этот счет.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Завтра поставлю еще несколько экспериментов. На данный момент могу только предположить какой-то глюк.
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 533
  • Карма: 117
Что я делаю не так?
Могу предположить, что в случае неудачи _fileDb занят, и не может сразу перейти к следующей ReadDwgFile

Возможно так поможет, т.к. до _fileDb = _fileDb2; скорее всего код не дойдет в случае ошибки.
   
Код - C# [Выбрать]
  1. Database _fileDb;
  2.     try
  3.     {
  4.         Database _fileDb2 = new Database(false, true);
  5.         _fileDb2.ReadDwgFile(FileName, FileShare.ReadWrite, false, "");
  6.         _fileDb = _fileDb2;
  7.     }
  8.     catch
  9.     {
  10.         // На случай, если файл находится в режиме ReadOnly
  11.         string _copyName = Path.Combine(Path.GetTempPath(), Path.GetFileName(FileName));
  12.         File.Copy(FileName, _copyName, true);
  13.         Database _fileDb3 = new Database(false, true);
  14.         _fileDb3.ReadDwgFile(_copyName, FileShare.ReadWrite, false, "");
  15.         _fileDb = _fileDb3;
  16.     }

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Спасибо, завтра попробую :)
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
В общем, я перестал что либо понимать. Ну я явно неправильно пишу код.

Исходные данные: в каталоге болтается 28 файлв общим объемом 16 с небольшим метров.
Беру лисповой код:

Код - Auto/Visual Lisp [Выбрать]
  1. (defun time-log (folder / odbx conn file handle filesize)
  2.   ;; (time-log "C:\\Autodesk\\OpenClose")
  3.   (if (not *kpblc-acad*)
  4.     (setq *kpblc-acad* (vlax-get-acad-object))
  5.   ) ;_ end of if
  6.   (if (not *kpblc-adoc*)
  7.     (setq *kpblc-adoc* (vla-get-activedocument *kpblc-acad*))
  8.   ) ;_ end of if
  9.  
  10.   (setq file   "c:\\odbx.log"
  11.         handle (open file "w")
  12.   ) ;_ end of setq
  13.   (close handle)
  14.   (foreach item (_kpblc-browsefiles-in-directory-nested folder "*.dwg")
  15.     (setq filesize (vl-file-size item))
  16.     (setq odbx (_kpblc-odbx)
  17.           conn (_kpblc-odbx-open item odbx)
  18.     ) ;_ end of setq
  19.     (setq handle (open file "a"))
  20.     (write-line (strcat (_kpblc-conv-date-to-string)
  21.                         "\topen "
  22.                         item
  23.                         "\t"
  24.                         (_kpblc-conv-value-to-string filesize)
  25.                         "\t"
  26.                         (_kpblc-conv-value-to-string (vla-get-count (vla-get-modelspace (cdr (assoc "obj" conn)))))
  27.                 ) ;_ end of strcat
  28.                 handle
  29.     ) ;_ end of write-line
  30.     (close handle)
  31.     (_kpblc-odbx-close odbx)
  32.     (setq handle (open file "a"))
  33.     (write-line (strcat (_kpblc-conv-date-to-string) "\tclose " item "\n") handle)
  34.     (close handle)
  35.   ) ;_ end of FOREACH
  36. ) ;_ end of defun

На выходе лог с примерно таким содержанием:
Извините, вам запрещён просмотр содержимого спойлеров.
Как видно, сработало практически мгновенно: на все-про-все ушло чуть больше чем полминуты

Беру код из NET

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices.Core;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.Runtime;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9.  
  10. namespace TestOpenClose.AcadCommands
  11. {
  12.     public static class TestOpenCloseDwg
  13.     {
  14.         [CommandMethod("test1", CommandFlags.Session)]
  15.         public static void TestOpenCloseWithLog()
  16.         {
  17.             LogService log = new LogService(@"c:\net.log");
  18.  
  19.             Database curDwgDatabase = Application.DocumentManager.MdiActiveDocument.Database;
  20.  
  21.             List<string> fileNames = new List<string>(Directory.GetFiles(_folder, "*.dwg", SearchOption.AllDirectories));
  22.  
  23.             foreach (string fileName in fileNames)
  24.             {
  25.                 Database _fileDatabase = new Database(false, true);
  26.                 using (WorkingDatabaseSwitcher dbSwitcher = new WorkingDatabaseSwitcher(_fileDatabase))
  27.                 {
  28.                     try
  29.                     {
  30.                         _fileDatabase.ReadDwgFile(fileName, FileShare.Read, false, "");
  31.                     }
  32.                     catch
  33.                     {
  34.                         string _copyFileName = Path.Combine(Path.GetTempPath(), Path.GetFileName(fileName));
  35.                         File.Copy(fileName, _copyFileName, true);
  36.                         _fileDatabase.ReadDwgFile(_copyFileName, FileShare.Read, false, "");
  37.                     }
  38.  
  39.                     _fileDatabase.CloseInput(true);
  40.  
  41.                     using (Transaction trans = _fileDatabase.TransactionManager.StartTransaction())
  42.                     {
  43.                         BlockTable blockTable =
  44.                             (BlockTable)trans.GetObject(_fileDatabase.BlockTableId, OpenMode.ForRead);
  45.  
  46.                         BlockTableRecord modelSpace =
  47.                             (BlockTableRecord)trans.GetObject(blockTable[BlockTableRecord.ModelSpace],
  48.                                 OpenMode.ForRead);
  49.  
  50.                         log.OpenFileLog(fileName, modelSpace.OfType<ObjectId>().Count());
  51.                     }
  52.                 }
  53.                 log.CloseFileLog(fileName);
  54.             }
  55.         }
  56.  
  57.         [CommandMethod("test2", CommandFlags.Session)]
  58.         public static void TestOpenCloseWithLogNoModel()
  59.         {
  60.             LogService log = new LogService(@"c:\netNoModel.log");
  61.  
  62.             Database curDwgDatabase = Application.DocumentManager.MdiActiveDocument.Database;
  63.  
  64.             List<string> fileNames = new List<string>(Directory.GetFiles(_folder, "*.dwg", SearchOption.AllDirectories));
  65.  
  66.             foreach (string fileName in fileNames)
  67.             {
  68.                 Database _fileDatabase = new Database(false, true);
  69.                 using (WorkingDatabaseSwitcher dbSwitcher = new WorkingDatabaseSwitcher(_fileDatabase))
  70.                 {
  71.                     try
  72.                     {
  73.                         _fileDatabase.ReadDwgFile(fileName, FileShare.Read, false, "");
  74.                     }
  75.                     catch
  76.                     {
  77.                         string _copyFileName = Path.Combine(Path.GetTempPath(), Path.GetFileName(fileName));
  78.                         File.Copy(fileName, _copyFileName, true);
  79.                         _fileDatabase.ReadDwgFile(_copyFileName, FileShare.Read, false, "");
  80.                     }
  81.                     log.OpenFileLog(fileName);
  82.  
  83.                     _fileDatabase.CloseInput(true);
  84.                 }
  85.                 log.CloseFileLog(fileName);
  86.             }
  87.         }
  88.  
  89.         [CommandMethod("test3", CommandFlags.Session)]
  90.         public static void TestOpenCloseWithLogDiffDbases()
  91.         {
  92.             LogService log = new LogService(@"c:\net_using.log");
  93.  
  94.             Database curDwgDatabase = Application.DocumentManager.MdiActiveDocument.Database;
  95.  
  96.             List<string> fileNames = new List<string>(Directory.GetFiles(_folder, "*.dwg", SearchOption.AllDirectories));
  97.  
  98.             foreach (string fileName in fileNames)
  99.             {
  100.                 log.OpenFileLog(fileName);
  101.  
  102.                 using (Database db = new Database(false, true))
  103.                 {
  104.                     db.ReadDwgFile(fileName, FileShare.Read, false, "");
  105.                     HostApplicationServices.WorkingDatabase = db;
  106.                 }
  107.  
  108.                 log.CloseFileLog(fileName);
  109.             }
  110.  
  111.             HostApplicationServices.WorkingDatabase = curDwgDatabase;
  112.         }
  113.  
  114.         private static string _folder = @"C:\Autodesk\OpenClose";
  115.     }
  116.  
  117.     public class LogService
  118.     {
  119.         public LogService(string LogFileName)
  120.         {
  121.             _logFile = LogFileName;
  122.             if (File.Exists(_logFile))
  123.             {
  124.                 File.Delete(_logFile);
  125.             }
  126.         }
  127.  
  128.         public void OpenFileLog(string FileName, int? ModelSpaceCount = null)
  129.         {
  130.             LogMessage(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\tstart " + FileName + "\t" +
  131.                        new FileInfo(FileName).Length + "\t" + (ModelSpaceCount == null
  132.                            ? ""
  133.                            : $"\t{ModelSpaceCount}"));
  134.         }
  135.  
  136.         public void CloseFileLog(string FileName)
  137.         {
  138.             LogMessage($"{DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")}\tclose {FileName}");
  139.         }
  140.  
  141.         private void LogMessage(string Message)
  142.         {
  143.             using (StreamWriter sw = new StreamWriter(_logFile, true, Encoding.UTF8))
  144.             {
  145.                 sw.WriteLine(Message);
  146.             }
  147.         }
  148.         private string _logFile;
  149.     }
  150.  
  151.     internal sealed class WorkingDatabaseSwitcher : IDisposable
  152.     {
  153.         public WorkingDatabaseSwitcher(Database db)
  154.         {
  155.             _prevDb = HostApplicationServices.WorkingDatabase;
  156.             HostApplicationServices.WorkingDatabase = db;
  157.         }
  158.         private Database _prevDb = null;
  159.  
  160.         public void Dispose()
  161.         {
  162.             HostApplicationServices.WorkingDatabase = _prevDb;
  163.         }
  164.     }
  165.  
  166. }

И тут результаты становятся такими:

Test1 -> 3,5 минуты
Извините, вам запрещён просмотр содержимого спойлеров.
 
Test2 -> 4 минуты
Извините, вам запрещён просмотр содержимого спойлеров.
 
Test3 -> 4 минуты
Извините, вам запрещён просмотр содержимого спойлеров.
 
Что в моем NET-коде настолько не так, что NET работает в 7-8 раз медленнее?
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
В результате нескольких экспериментов на нескольких машинах. Ситуация повторяется на Win7 + ACAD2013. Win10 + ACAD20[19/20/21] - все работает шустро, как и должно. Получается, проблема в версии ACAD ?! А что мне делать, если надо именно под эту древнюю, как ***** мамонта, версию?
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 533
  • Карма: 117
А что мне делать, если надо именно под эту древнюю, как ***** мамонта, версию?
Возможно причина не совсем в версии.
Можно попробовать прогнать сперва стопку пустых, вновь созданных файлов файлов. Если все быстро, то надежда есть.
Затем прогнать боевые файлы и замерить время для каждого. И если повезет, то будет к примеру 3 файла, которые долго грузятся.
Посмотреть их. Что собственно может быть, да например долго обрабатываются отсутствующие ссылки или SPDS extension или еще какое-то приложение и его прокси, словари и т.д. замедляют работу при загрузке в данной версии.
Может и решение найдется

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Там из всех возможных прокси - максимум wipeout'ы. Пустые файлы не гонял, а время замерял. Практически полностью совпадает с вариантом полноценной загрузки файла в ACAD.
Проблема в том, что менять файлы запрещено, и надо работать с тем, что есть :( Я так не хочу это на лиспе писать! ;(
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн doctorRAZ

  • ADN OPEN
  • Сообщений: 42
  • Карма: 0
  • Skype: doctorraz
Мало ли.. спрошу
Ты же в студии в отладке пошагово свой код прогонял?
Студия пишет время затраченное на каждую операцию..
К тому, что можно конкретно посмотреть на какой операции или файле тупит..

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Смотрел, конечно, и пошагово в том числе. Как раз на ReadDwgFile и тормоза. Все остальное отрабатывает на ура. Когда перестал себе верить, стал в лог выводить.
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 533
  • Карма: 117
Как раз на ReadDwgFile и тормоза
Чистый AutoCAD, без приложений? Сервис паки установлены? Если все так, можно попробовать отключить антивирусник, посмотреть реакцию.
Если ничего не помогает, то принять и простить.

Можно попробовать загрузить данные во втором потоке, вдруг прокатит. Создать поток, создать в нем _fileDatabase, вызвать ReadDwgFile и по завершению вернуть _fileDatabase  в основной поток. В основном потоке пытаться что-то считать/модифицировать.

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Похоже, придется именно "принять и похоронить" :( Со многопоточностью я не дружу, к моему великому сожалению. Попробую, конечно, найти какие-нибудь примеры...
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Lemieux

  • ADN OPEN
  • ****
  • Сообщений: 379
  • Карма: 21
Можно попробовать загрузить данные во втором потоке, вдруг прокатит. Создать поток, создать в нем _fileDatabase, вызвать ReadDwgFile и по завершению вернуть _fileDatabase  в основной поток. В основном потоке пытаться что-то считать/модифицировать.
По своему опыту могу сказать, что даже запуск в другом потоке любого приложения, из основного потока AutoCAD, а потом снова обращение к AutoCAD выдаёт ошибку. Только если сначала запускать выполнение AutoCAD, а потом других программ. У меня так работает AutoCAD, Excel. Но async/await ни при каких условиях не работает, только Parallel.Invoke.

Если нужна пакетная обработка, то можно посмотреть в сторону AcCoreConsole, но там тоже есть ограничения.

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Значит можно даже и не пытаться :) Спасибо ;)
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Алексей Кулик,
А ты не пробовал использовать конструктор Database(false, false); ?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Значит можно даже и не пытаться  Спасибо
А попробовать с accoreconsole?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн doctorRAZ

  • ADN OPEN
  • Сообщений: 42
  • Карма: 0
  • Skype: doctorraz
А попробовать с accoreconsole?
по условиям задачи
В результате нескольких экспериментов на нескольких машинах. Ситуация повторяется на Win7 + ACAD2013. Win10 + ACAD20[19/20/21] - все работает шустро, как и должно. Получается, проблема в версии ACAD ?! А что мне делать, если надо именно под эту древнюю, как ***** мамонта, версию?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
doctorRAZ,
Не вижу противоречия - в AutoCAD 2013 есть своя AcCoreConsole.exe
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей КуликАвтор темы

  • Administrator
  • *****
  • Сообщений: 1096
  • Карма: 172
Алексей Кулик,
А ты не пробовал использовать конструктор Database(false, false); ?
Попробую, но уже завтра. На данный момент нет ни данных, ни сил, не желания ковыряться ;) Но обязательно попробую, спасибо!
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!