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

ADN Club => AutoCAD .NET API => Тема начата: Lemieux от 08-11-2020, 21:20:35

Название: Parallel.Invoke
Отправлено: Lemieux от 08-11-2020, 21:20:35
Всех приветствуют. Кто-нибудь на форуме пользуется в плагинах к AutoCAD Parallel.Invoke иди другими многопоточными фишками?
Меня интересует, вот что:

Такой шаблон не работает
Код - C# [Выбрать]
  1. Parallel.Invoke(
  2.   () =>
  3.   {
  4.     //Запускается и что-то делает не AutoCAD, например Excel
  5.   },
  6.   () =>
  7.   {
  8.     //Тут что-то делает AutoCAD, например добавляет лист и производит на нём операции
  9.   });

А вот такой работает
Код - C# [Выбрать]
  1. Parallel.Invoke(
  2.   () =>
  3.   {
  4.     //Тут что-то делает AutoCAD, например добавляет лист и производит на нём операции
  5.   },
  6.   () =>
  7.   {
  8.     //Запускается и что-то делает не AutoCAD, например Excel
  9.   });
Название: Re: Parallel.Invoke
Отправлено: Александр Ривилис от 08-11-2020, 21:23:45
Lemieux,
Обращение к AutoCAD API (любое - .NET/VisualLisp/VBA/ObjectARX) допустимо только из основного потока. Многопоточное обращение к AutoCAD запрещено. Точка!
Название: Re: Parallel.Invoke
Отправлено: Lemieux от 08-11-2020, 21:31:01
Lemieux,
Обращение к AutoCAD API (любое - .NET/VisualLisp/VBA/ObjectARX) допустимо только из основного потока. Многопоточное обращение к AutoCAD запрещено. Точка!
Получается, что во втором варианте я обращаюсь из основного потока, если всё работает?
Название: Re: Parallel.Invoke
Отправлено: Александр Ривилис от 08-11-2020, 21:36:06
Получается, что во втором варианте я обращаюсь из основного потока, если всё работает?
Видимо да, хотя я не видел, чтобы это было где-то документировано. Но если вдруг, в какой-то ситуации это окажется нет так, то пользователя твоей программы сразу возникнут проблемы.
Название: Re: Parallel.Invoke
Отправлено: Lemieux от 08-11-2020, 21:55:08
Обращение к AutoCAD API (любое - .NET/VisualLisp/VBA/ObjectARX) допустимо только из основного потока. Многопоточное обращение к AutoCAD запрещено. Точка!
Что и требовалось доказать.
С Parallel.ForEach не получилось, выдаёт ошибку "Операция является недопустимой из-за текущего состояния объекта", когда в транзакции вызываю метод GetObject(). Хотя первые двадцать итераций ошибки не выдавало, но мне лень щелкать 200 раз. Но меня смутило то, что во время итерации отладчик подсвечивал не в цикле, а в LINQ запросе (я блоки в пространстве модели получаю через LINQ запрос).
Название: Re: Parallel.Invoke
Отправлено: avc от 08-11-2020, 22:22:17
Если есть в самом деле сложная задача, то ее можно распараллелить. Просто надо считать данные из чертежа в свои структуры, обработать параллельно, не вызывая API, и потом уже сохранять результаты в чертеж в главном процессе. По моему опыту структуры из API и их методы можно вызывать из других потоков безболезненно (Point2d, Vector3d и т.п.) Еще ProgressMeter вызываю - ничего, не фаталит. Но конечно не объекты из транзакций получать.
Название: Re: Parallel.Invoke
Отправлено: Lemieux от 09-11-2020, 20:50:45
Если есть в самом деле сложная задача, то ее можно распараллелить. Просто надо считать данные из чертежа в свои структуры, обработать параллельно, не вызывая API, и потом уже сохранять результаты в чертеж в главном процессе. По моему опыту структуры из API и их методы можно вызывать из других потоков безболезненно (Point2d, Vector3d и т.п.) Еще ProgressMeter вызываю - ничего, не фаталит. Но конечно не объекты из транзакций получать.
Зачем делать двойную работу? Сначала считывать, потом обрабатывать и потом всё это объединять? Я тут попробовал провести эксперимент. Думал получу все блоки из пространства модели, получу количество доступных потоков, разобью список на количество потоков и сделаю массив из Action с нужными мне действиями по чтению нужной информации из блоков и засуну эти Action в Parallel.Invoke. Но AutoCAD ругается, странно, что фича с Excel/Word работает.
Название: Re: Parallel.Invoke
Отправлено: avc от 09-11-2020, 21:12:29
Про это уже было сказано вполне однозначно. Читать и записывать данные в чертеж -только в одном потоке. Автокад не эксел, шуток не понимает. Зачем вы опять экспериментируете?
И нет никакой двойной работы - есть работа со считанными данными. И если она достаточно большая, то имеет смысл отделять чтение/хранение/обработку/запись.  Если несущественная - не имеет смысла - работайте в одном потоке.
Название: Re: Parallel.Invoke
Отправлено: Lemieux от 09-11-2020, 21:23:06
Зачем вы опять экспериментируете?
Потому что интересно.

PS пришла идея с "AcCoreConsole.exe", но пока не буду городить огород, так как действительно больших проектов нет. Но если буду проекты где 500-1000 блоков в пространстве модели, то буду думать. Или если будет свободное время.
Название: Re: Parallel.Invoke
Отправлено: avc от 09-11-2020, 22:16:22
1000 блоков - это мизер. Сейчас делал плагин для чистки чертежа после импорта pdf. Там по 350 тысяч объектов сразу читывать приходится. Панель свойств впадает в ступор. Но простой цикл чтения foreach без малейшей параллельности считывает это за 2 секунды. Что тут параллелить и зачем?
Название: Re: Parallel.Invoke
Отправлено: Lemieux от 10-11-2020, 08:08:56
1000 блоков - это мизер. Сейчас делал плагин для чистки чертежа после импорта pdf. Там по 350 тысяч объектов сразу читывать приходится. Панель свойств впадает в ступор. Но простой цикл чтения foreach без малейшей параллельности считывает это за 2 секунды. Что тут параллелить и зачем?
Что считывает, блоки из пространства модели? Но мне надо работать с атрибутами блоков, которых в блоке может быть много.
Название: Re: Parallel.Invoke
Отправлено: Привалов Дмитрий от 10-11-2020, 12:31:24
Что считывает, блоки из пространства модели? Но мне надо работать с атрибутами блоков, которых в блоке может быть много.
AutoCAD это хорошо оптимизированное однопоточное приложение при работе с БД чертежа. По опыту, производительности хватает на обработку/изменение данных.

мне надо работать с атрибутами блоков, которых в блоке может быть много.
Ты можешь в основном потоке считать информацию из атрибутов в массивы/классы, обработать Parallel.Invoke и в основном потоке изменить атрибуты.
Название: Re: Parallel.Invoke
Отправлено: Александр Ривилис от 10-11-2020, 12:41:19
Lemieux,
У меня есть приложение DWGCONVERT, которое полностью проходит по ВСЕМУ чертежу и меняет кодировку текстов, атрибутов, наименований слоёв, блоков, стилей и т.д. Так вот какой-нибудь чертеж может открываться несколько минут, а программа отрабатывает (модифицирует его полностью) за секунды. И при этом она однопоточная.
Название: Re: Parallel.Invoke
Отправлено: Lemieux от 10-11-2020, 14:28:59
Ты можешь в основном потоке считать информацию из атрибутов в массивы/классы, обработать Parallel.Invoke и в основном потоке изменить атрибуты.
Так я нигде не писал, что мне надо изменять атрибуты, я их считываю, но у меня 5 условий при считывании атрибутов. И в цикле происходит анализ всех атрибутов, а запись в нужные массивы происходит не из всех атрибутов, а только удовлетворяющих условиям.

а программа отрабатывает (модифицирует его полностью) за секунды
Допустим у меня команда отрабатывает за 5 секунд, но был интересен сам факт распараллеливания и новой информации.
Название: Re: Parallel.Invoke
Отправлено: Привалов Дмитрий от 10-11-2020, 15:17:22
но у меня 5 условий при считывании атрибутов. И в цикле происходит анализ всех атрибутов, а запись в нужные массивы происходит не из всех атрибутов, а только удовлетворяющих условиям.

Допустим у меня команда отрабатывает за 5 секунд, но был интересен сам факт распараллеливания и новой информации.

Разбей задачу на 2 части:
1. Считывай все атрибуты в массивы(или что у тебя там) за один проход и замерь время. 
2. Посмотри сколько времени занимает анализ атрибутов.

Вполне возможно, что 4 секунды тратились на анализ. Вот и будешь оптимизировать его хоть с Parallel.Invoke, хоть без.
Название: Re: Parallel.Invoke
Отправлено: avc от 11-11-2020, 12:02:08
Просто любопытное наблюдение по теме Parallel.ForEach:
Если сохранить ObjectId объектов чертежа, а затем в параллельном цикле проверять id.IsNull и id.IsErased - все прекрасно работает.
НО! Как только добавляем проверку id.IsValid - цикл начинает колбасить. Причем ооочень странно колбасить. Ни ошибок, ни фаталов. Просто цикл выполняется не над всеми объектами списка. Иногда не выполняются инструкции находящиеся даже ДО проверки IsValid. Я вставил в тело процедуры несколько счетчиков и несколько раз видел парадоксальный результат - счетчик в самом начале процедуры "натикал" меньше, чем в конце, после всех условий. Этого вообще никак не может быть, но факт...
Вывод - структуры из API тоже могут лезть в чертеж в самые неожиданные моменты и вызывать самые неожиданные глюки.
Название: Re: Parallel.Invoke
Отправлено: Александр Ривилис от 11-11-2020, 12:21:44
Как только добавляем проверку id.IsValid - цикл начинает колбасить.
Так и должно быть. Ведь для того, чтобы проверить корректность ObjectId, AutoCAD должен полезть в базу данных. id.IsNull очевидно проверяет на 0 равенство одно из полей, id.IsErased тоже вполне возможно считывает некое поле в самом ObjectId, не обращаясь к базе.