Async/Await/Paralle

Автор Тема: Async/Await/Paralle  (Прочитано 7414 раз)

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

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн LemieuxАвтор темы

  • ADN OPEN
  • ****
  • Сообщений: 389
  • Карма: 21
Async/Await/Paralle
« : 27-02-2021, 17:50:03 »
Может и была тема, и я как всегда плохо искал, но поделюсь мыслями.

Понадобилось мне в 100500 файлах поменять веса линий в слоёв. Я написал код, который последовательно перебирает все файлы и делает, что надо. Потом я решил прикрутить async/await - заработало, потом решил прикрутить Parallel - заработало.
Для теста я взял примерно 20 папок, разной степени вложенности, и примерно 200 файлов. Результаты такие:
async/await - 23 секунды, интерфейс не блокируется
Paralle - 23 секунды, интерфейс блокируется
Стандартно - 30 секунд, интерфейс блокируется.
Процессор Xeon - 1230v3.
Самый лучший вариант async/await в данной ситуации, но мне непонятно почему такая небольшая разница относительно стандартного варианта. Вот код, может я что-то неправильно реализую. И ещё я не пробовал запускать несколько экземпляров AcCoreConsole.

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Application = Autodesk.AutoCAD.ApplicationServices.Application;
  4. using System.IO;
  5. using System.Threading.Tasks;
  6. using System.Windows.Forms;
  7.  
  8. namespace LineWeightChange
  9. {
  10.     public class Commands
  11.     {
  12.         [CommandMethod("ASYNCMETHOD")]
  13.         public async void AsyncMethod()
  14.         {
  15.             string result = Browser();
  16.             if (result != "")
  17.             {
  18.                 bool taskResult = await Task.Run(() => AsyncWorkWithDirectories(result));
  19.                 if (taskResult)
  20.                     Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nCOMPLETE\n");
  21.             }
  22.         }
  23.  
  24.         [CommandMethod("PARALLELMETHOD")]
  25.         public void ParallelMethod()
  26.         {
  27.             string result = Browser();
  28.             if (result != "")
  29.             {
  30.                 Parallel.Invoke(() => ParallelWorkWithDirectories(result));
  31.                 Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nCOMPLETE\n");
  32.             }
  33.         }
  34.  
  35.         [CommandMethod("STANDARDMETHOD")]
  36.         public void StandardMethod()
  37.         {
  38.             string result = Browser();
  39.             if (result != "")
  40.             {
  41.                 StandardWorkWithDirectories(result);
  42.                 Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nCOMPLETE\n");
  43.             }
  44.         }
  45.  
  46.         private void WorkWithDrawing(string path)
  47.         {
  48.             using (Database database = new Database(false, true))
  49.             {
  50.                 database.ReadDwgFile(path, FileOpenMode.OpenForReadAndWriteNoShare, true, null);
  51.                 using (Transaction tr = database.TransactionManager.StartTransaction())
  52.                 {
  53.                     LayerTable layerTable = tr.GetObject(database.LayerTableId, OpenMode.ForWrite) as LayerTable;
  54.                     if (layerTable.Has("SolidThick"))
  55.                     {
  56.                         LayerTableRecord layer = tr.GetObject(layerTable["SolidThick"], OpenMode.ForWrite) as LayerTableRecord;
  57.                         layer.LineWeight = LineWeight.LineWeight050;
  58.                     }
  59.                     if (layerTable.Has("SolidThin"))
  60.                     {
  61.                         LayerTableRecord layer = tr.GetObject(layerTable["SolidThin"], OpenMode.ForWrite) as LayerTableRecord;
  62.                         layer.LineWeight = LineWeight.ByLineWeightDefault;
  63.                     }
  64.                     tr.Commit();
  65.                 }
  66.                 SecurityParameters security = Application.DocumentManager.MdiActiveDocument.Database.SecurityParameters;
  67.                 database.SaveAs(path, true, DwgVersion.AC1024, security);
  68.             }
  69.         }
  70.  
  71.         private async Task<bool> AsyncWorkWithDirectories(string path)
  72.         {
  73.             bool result = true;
  74.             DirectoryInfo currentDirectory = new DirectoryInfo(path);
  75.             DirectoryInfo[] directories = currentDirectory.GetDirectories();
  76.             foreach (DirectoryInfo directory in directories)
  77.             {
  78.                 FileInfo[] files = directory.GetFiles();
  79.                 foreach (FileInfo file in files)
  80.                     if (file.Extension == ".dwg")
  81.                         await Task.Run(() => WorkWithDrawing(file.FullName));
  82.                 result = await Task.Run(() => AsyncWorkWithDirectories(directory.FullName));
  83.             }
  84.             return result;
  85.         }
  86.  
  87.         private void ParallelWorkWithDirectories(string path)
  88.         {
  89.             DirectoryInfo currentDirectory = new DirectoryInfo(path);
  90.             DirectoryInfo[] directories = currentDirectory.GetDirectories();
  91.             foreach (DirectoryInfo directory in directories)
  92.             {
  93.                 FileInfo[] files = directory.GetFiles();
  94.                 foreach (FileInfo file in files)
  95.                     if (file.Extension == ".dwg")
  96.                         Parallel.Invoke(() => WorkWithDrawing(file.FullName));
  97.                 Parallel.Invoke(() => ParallelWorkWithDirectories(directory.FullName));
  98.             }
  99.         }
  100.  
  101.         private void StandardWorkWithDirectories(string path)
  102.         {
  103.             DirectoryInfo currentDirectory = new DirectoryInfo(path);
  104.             DirectoryInfo[] directories = currentDirectory.GetDirectories();
  105.             foreach (DirectoryInfo directory in directories)
  106.             {
  107.                 FileInfo[] files = directory.GetFiles();
  108.                 foreach (FileInfo file in files)
  109.                     if (file.Extension == ".dwg")
  110.                         WorkWithDrawing(file.FullName);
  111.                 StandardWorkWithDirectories(directory.FullName);
  112.             }
  113.         }
  114.  
  115.         private string Browser()
  116.         {
  117.             FolderBrowserDialog browser = new FolderBrowserDialog
  118.             {
  119.                 Description = "Some description",
  120.                 ShowNewFolderButton = false
  121.             };
  122.             browser.ShowDialog();
  123.             return browser.SelectedPath;
  124.         }
  125.     }
  126. }

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Async/Await/Paralle
« Ответ #1 : 27-02-2021, 17:56:36 »
но мне непонятно почему такая небольшая разница относительно стандартного варианта.
Потому что AutoCAD API однозадачный. И вообще всё что ты сделал крайне небезопасно. С AutoCAD API можно работать только из главной задачи AutoCAD.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн LemieuxАвтор темы

  • ADN OPEN
  • ****
  • Сообщений: 389
  • Карма: 21
Re: Async/Await/Paralle
« Ответ #2 : 27-02-2021, 18:05:42 »
С AutoCAD API можно работать только из главной задачи AutoCAD.
Ну, мне же никто не запрещает создавать бесконечное количество Database и работать с ними? Я не понимаю, что такого запретного в параллельной работе, AutoCAD не ломается, не ругается, выборочные чертежи нормально открываются и с ними можно работать.

Отмечено как Решение Lemieux 27-02-2021, 18:09:24

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Async/Await/Paralle
« Ответ #3 : 27-02-2021, 18:08:27 »
Lemieux,
Я всё сказал выше. Повторяться не буду.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн LemieuxАвтор темы

  • ADN OPEN
  • ****
  • Сообщений: 389
  • Карма: 21
Re: Async/Await/Paralle
« Ответ #4 : 27-02-2021, 18:09:46 »
Lemieux,
Я всё сказал выше. Повторяться не буду.
Я всё понял  ::)

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

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Async/Await/Paralle
« Ответ #5 : 27-02-2021, 22:57:24 »
но мне непонятно почему такая небольшая разница относительно стандартного варианта. Вот код, может я что-то неправильно реализую.

решил прикрутить async/await - заработало, потом решил прикрутить Parallel - заработало.
Это ответ на твой же вопрос.
Прикрутить и знать+уметь пользоваться, это разные вещи!

Твой код не запускает параллельно несколько задач, как ты наверное ожидал. Он запускает выполнение одной задачи в другом потоке(ядре) и ждет.

Твой манипуляции с БД достаточно просты, я имею ввиду метод WorkWithDrawing.
Возможно в таком контексте это может работать параллельно основному потоку.
Можно ли запустить параллельно несколько методов WorkWithDrawing вопрос интересный, небольшой шанс есть.

Если ты попытаешься в метод WorkWithDrawing вставить Task.Run, либо попытаешься параллельно обращаться к одной и той же Database то вероятно обрушишь Автокад. Это люди уже пробовали, не получилось :-).

Я не понимаю, что такого запретного в параллельной работе, AutoCAD не ломается, не ругается, выборочные чертежи нормально открываются и с ними можно работать.
Никто тебе не запрещает и не ограничивает, делай что хочешь. Просто движек автокада никто специально не делает, не тестирует и т.д. на параллельный доступ к данным. Соответственно когда у тебя что-то упадет или поломается не удивляйся, тебя предупредили что это не предусмотрено.