Parallel task

Parallel task

d.fedulov
Participant Participant
536 Views
3 Replies
Message 1 of 4

Parallel task

d.fedulov
Participant
Participant

Hello. I have a program to store element properties to csv file.  I want to parallelize the processing of items, but the Navisworks closes with an error. Please help me find the error.

var fileContent = string.Empty;
            var filePath = string.Empty;
            var filePathResult = string.Empty;
            string tempString;
            byte i, j;
  
            List<List<string>> listOfLists = new List<List<string>>();
            var fileStrings = new List<string>();
            object locker = 0;  // объект-заглушка для локера в потоках

            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
                openFileDialog.FilterIndex = 2;
                openFileDialog.RestoreDirectory = true;

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    //Get the path of specified file
                    filePath = openFileDialog.FileName;
                    filePathResult = openFileDialog.FileName.Remove(openFileDialog.FileName.IndexOf(openFileDialog.SafeFileName)); //сохраняем папку для записи результатов
                                                                                                                                   //Read the contents of the file into a stream
                    var fileStream = openFileDialog.OpenFile();

                    using (StreamReader reader = new StreamReader(fileStream, System.Text.Encoding.Default))
                    {
                        //fileContent = reader.ReadToEnd();

                        while (!reader.EndOfStream)
                        {
                            string line = reader.ReadLine();
                            fileStrings.Add(line);

                        }
                    }
                }
                else
                { return 0; }
            }

            for (i = 0; i < fileStrings.Count(); i++)
            {
                listOfLists.Add(fileStrings[i].Split(';').ToList());  //делаем список списков слов из файла, разделенных точкой с запятой
            }

            int attr_count = 0;
            StreamWriter sw = new StreamWriter(filePathResult + "Test.txt", false, System.Text.Encoding.Default);//открываем файл для записи результатов
            tempString = "";
            for (i = 0; i < listOfLists.Count(); i++)
            {
                attr_count = attr_count + listOfLists[i].Count() - 1;        //считаем количество свойств дл создания массива значений свойств
                for (j = 1; j < listOfLists[i].Count(); j++)
                {
                    tempString = tempString + listOfLists[i][0] + " " + listOfLists[i][j] + ";";    //формируем шапку таблицы "вкладка/свойстов"       
                }
            }
            sw.WriteLine(tempString);  //записываем шапку таблицы с наименованиями свойств

            Document oDoc = Autodesk.Navisworks.Api.Application.ActiveDocument;
            int ItemCount = oDoc.CurrentSelection.SelectedItems.Count;

            Progress progress = Autodesk.Navisworks.Api.Application.BeginProgress();    //создаем и запускаем индикатор процесса
            double step = 0;

            Parallel.ForEach(oDoc.CurrentSelection.SelectedItems, SaveProp);
            void SaveProp(ModelItem oItem)
            {
                int ii, jj, kk;
                string[] attr_value = new string[attr_count];       //создаем массив для хранения значений свойств
                foreach (PropertyCategory oPC in oItem.PropertyCategories)
                {
                    kk = 0; 
                    for (ii = 0; ii < listOfLists.Count(); ii++)
                    {
                        
                        if (listOfLists[ii][0] == oPC.DisplayName.ToString())
                        {
                            foreach (DataProperty oDP in oPC.Properties)
                            {
                                for (jj = 1; jj < listOfLists[ii].Count(); jj++)
                                {
                                    
                                    if (oDP.DisplayName.ToString() == listOfLists[ii][jj]) //ищем совпадение имени свойств
                                    {
                                        switch (oDP.Value.DataType)
                                        {
                                            case VariantDataType.Boolean: attr_value[kk + jj - 1] = oDP.Value.ToBoolean().ToString(); break;
                                            case VariantDataType.DisplayString: attr_value[kk + jj - 1] = oDP.Value.ToDisplayString(); break;
                                            case VariantDataType.IdentifierString: attr_value[kk + jj - 1] = oDP.Value.ToIdentifierString(); break;
                                            case VariantDataType.Int32: attr_value[kk + jj - 1] = oDP.Value.ToInt32().ToString(); break;
                                            case VariantDataType.Double: attr_value[kk + jj - 1] = oDP.Value.ToDouble().ToString(); break;
                                            case VariantDataType.DoubleAngle: attr_value[kk + jj - 1] = oDP.Value.ToDoubleAngle().ToString(); break;
                                            case VariantDataType.DoubleArea: attr_value[kk + jj - 1] = (oDP.Value.ToDoubleArea() * 0.092903).ToString(); break;
                                            case VariantDataType.DoubleLength: attr_value[kk + jj - 1] = (oDP.Value.ToDoubleLength() * 0.3048).ToString(); break;
                                            case VariantDataType.DoubleVolume: attr_value[kk + jj - 1] = (oDP.Value.ToDoubleVolume() * 0.0283168).ToString(); break;
                                            case VariantDataType.DateTime: attr_value[kk + jj - 1] = oDP.Value.ToDateTime().ToString(); break;
                                            case VariantDataType.NamedConstant: attr_value[kk + jj - 1] = oDP.Value.ToNamedConstant().ToString(); break;
                                            case VariantDataType.Point3D: attr_value[kk + jj - 1] = oDP.Value.ToPoint3D().ToString(); break;
                                            case VariantDataType.Point2D: attr_value[kk + jj - 1] = oDP.Value.ToPoint2D().ToString(); break;
                                            case VariantDataType.None: break;
                                        }

                                    }
                                }
                            }
                        }
                        kk = kk + listOfLists[ii].Count() - 1;  //переменная для расчета номера позиции значения свойства
                    }


                }
                lock (locker)
                {
                    step += 1;
                    progress.Update(Math.Round(step / ItemCount, 3));          

                    if (progress.IsCanceled)                                     
                    {
                        sw.Close();                                             //закрываем файл результатов
                        Autodesk.Navisworks.Api.Application.EndProgress();      //закрываем индикатор процесса
                        return;
                    }

                    sw.WriteLine(String.Join(";", attr_value));                 
                }

            }
            sw.Close();                                                     
            Autodesk.Navisworks.Api.Application.EndProgress();              
            
            sw.Close();
            return 0;
        }

 

0 Likes
537 Views
3 Replies
Replies (3)
Message 2 of 4

alexisDVJML
Collaborator
Collaborator

Navisworks C# API is basically, as far as I understand, single-threaded/not thread safe.

Parallel.ForEach internally use thread, cf. for example https://www.albahari.com/threading/part5.aspx 

 

However, I had partial success in a few experiment, your mileage can vary.

 

In your case, did you try first your algorithm with a regular foreach loop?

Your code is quite complicated for me to look at it line by line 😉

 

If your code work with a regular foreach loop, what I would try is AT LEAST to remove the Progress handling from the Parallel code. I would guess this one sure will crash since it involves the UI 😉
also ensure everything you do is only readonly accesses and you could have a chance.

Let us know your progress since such use, while being officially not supported, could be useful 😉

Main Scientist, Full Stack Developer & When Time Permits Director of IDIGO ► On your marks, Set, Go
0 Likes
Message 3 of 4

d.fedulov
Participant
Participant

@alexisDVJML  написал (-а):

In your case, did you try first your algorithm with a regular foreach loop?

it works fine

 


@alexisDVJML  написал (-а):

If your code work with a regular foreach loop, what I would try is AT LEAST to remove the Progress handling from the Parallel code. I would guess this one sure will crash since it involves the UI 😉


i tried but it doesn't work

 


@alexisDVJML  написал (-а):

also ensure everything you do is only readonly accesses and you could have a chance.


only  StreamWriter  writes a file, i use lock operator

0 Likes
Message 4 of 4

alexisDVJML
Collaborator
Collaborator
OK.
I can see multiple reasons. Just one exemple: you lock on locker which is null, should be initialized, aka locker = new object();

What you could do is start with something really basic, iterating the ModelItemCollection and incrementing a volatile itemsCount, than slowly bring part of your algo..
Also a MUST is catching exceptions in your delegate, if you lucky with a breakpoint using debugger, you could identify the issue.
Main Scientist, Full Stack Developer & When Time Permits Director of IDIGO ► On your marks, Set, Go
0 Likes