Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Оптимизация функции замены строки / 14 сообщений из 14, страница 1 из 1
30.08.2013, 16:09
    #38382565
Testor1
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Всем привет!

Требуется из csv строки удалить ненужны значения. Функция работает, но для больших объемов данных производительность низкая. Профайлеру не нравиться эта строка input[i] == delimiter. Как можно оптимизировать код?

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
        public static String csv_remove_unused_data(String input, Char delimiter, ref Boolean[] columns)
        {

            StringBuilder output = new StringBuilder();
            Int32 column = 0;
            String Delimeter = delimiter.ToString();
            Int32 length = input.Length;
            Int32 startPosition = 0;

            for (int i = 0; i < length; i++)
            {
                if (input[i] == delimiter)
                {
                    column++;
                    if(columns[column]) 
                        output.Append(input.Substring(startPosition, i-startPosition+1).ToString());
                    else 
                        output.Append(@"|");
                    startPosition = i + 1;
                }
            }
            if (columns[column]) 
                output.Append(input.Substring(startPosition, length - startPosition).ToString());

                return output.ToString();
        }
...
Рейтинг: 0 / 0
02.09.2013, 07:05
    #38383770
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Testor1,

String.IndexOf ?
...
Рейтинг: 0 / 0
02.09.2013, 08:40
    #38383792
Ermak
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Попробуй использовать рег. выражения. Возможно, что будет работать быстрее
...
Рейтинг: 0 / 0
02.09.2013, 12:15
    #38384001
Testor1
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Alex KuznetsovTestor1,

String.IndexOf ?

Он медленее
...
Рейтинг: 0 / 0
02.09.2013, 12:15
    #38384002
Testor1
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
ErmakПопробуй использовать рег. выражения. Возможно, что будет работать быстрее

Рег выражения по определению медленные.
...
Рейтинг: 0 / 0
02.09.2013, 13:00
    #38384061
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Testor1Alex KuznetsovTestor1,

String.IndexOf ?

Он медленееТогда работайте со строкой как с массивом Char...
Т.е. откажитесь от SubString...
...
Рейтинг: 0 / 0
02.09.2013, 13:26
    #38384082
Tamozhnya
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Alex KuznetsovTestor1пропущено...


Он медленееТогда работайте со строкой как с массивом Char...
Т.е. откажитесь от SubString...

SubString и так работает со строкой, как с массивом. Он сразу переходит к символу, по индексу, указанному в первом параметре.
Ни каких накладных расходов у него быть не должно (ну, т.е. он не бежит по всей строке и ничего в ней не ищет)
...
Рейтинг: 0 / 0
02.09.2013, 14:38
    #38384211
petalvik
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Testor1Как можно оптимизировать код?
При создании стрингбилдера указать размер, достаточный для вмещения данных: new StringBuilder(1000)
Если метод вызывается неоднократно, то стрингбилдер сделать полем класса, а в методе лишь очищать его: output.Clear();


String Delimeter = delimiter.ToString(); - это зачем? Просмотреть код, и выкинуть лишнее.


input.Substring(startPosition, i-startPosition+1).ToString() - аналогично, зачем ToString()? Убрать.


В данном случае будут проверки на вхождение индекса в границы:
Код: c#
1.
2.
Int32 length = input.Length;
for (int i = 0; i < length; i++)


Если переписать так:
Код: c#
1.
for (int i = 0; i < input.Length; i++)

то компилятор может выкинуть такие проверки.


output.Append(@"|"); - имхо, лучше будет написать output.Append('|'); то есть добавлять символ, а не строку - должно быть быстрее.
...
Рейтинг: 0 / 0
02.09.2013, 15:26
    #38384254
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
TamozhnyaAlex Kuznetsovпропущено...
Тогда работайте со строкой как с массивом Char...
Т.е. откажитесь от SubString...

SubString и так работает со строкой, как с массивом. Он сразу переходит к символу, по индексу, указанному в первом параметре.
Ни каких накладных расходов у него быть не должно (ну, т.е. он не бежит по всей строке и ничего в ней не ищет)А его вызовы не дают накладных расходов?
И его внутренние проверки на выход за пределы массива тоже ни на что не влияют?
Я же написал отказаться от вызова...
...
Рейтинг: 0 / 0
03.09.2013, 20:43
    #38385927
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Testor1,
а если вот так?
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
using System;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            bool[] cols = new bool[]{ false,false,true,false,false,true,true,false,true,false };
            string csvSource = "11111,22222,33333,44444,55555,66666,77777,88888,943023,1000000000";
            Console.WriteLine(csvSource);
            Console.WriteLine();
            for(int i = 0;i<1000;i++) Console.WriteLine(csv_remove_unused_data(csvSource, ',', ref cols));
            Console.WriteLine();
            Console.ReadLine();
        }


        static String csv_remove_unused_data(String input, Char delimiter, ref Boolean[] columns)
        {

            StringBuilder output = new StringBuilder(input.Length);
            Int32 column = 0;
            for (int i = 0; i < input.Length; i++)
            {
                if (input[i] == delimiter)
                {
                    column++;
                    output.Append(input[i]);
                }else{
                    if (!columns[column]) output.Append(input[i]);
                }
            }

            return output.ToString();
        }
    }
}

...
Рейтинг: 0 / 0
03.09.2013, 21:10
    #38385946
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Testor1,
ну а можно ещё и вот так:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
using System;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            bool[] cols = new bool[]{ false,false,true,false,false,true,true,false,true,false };
            string csvSource = "11111,22222,33333,44444,55555,66666,77777,88888,943023,1000000000";
            Console.WriteLine(csvSource);
            Console.WriteLine("csv_remove_unused_data");
            DateTime st = DateTime.Now;
            for(int i = 0;i<10000;i++)
             csv_remove_unused_data(csvSource, ',', ref cols);
            TimeSpan ts = DateTime.Now - st;
            Console.WriteLine("Result of csv_remove_unused_data: {0}", ts.TotalMilliseconds);
            Console.WriteLine();

            Console.WriteLine("csv_remove_unused_data_split");
            st = DateTime.Now;
            for (int i = 0; i < 10000; i++)
                csv_remove_unused_data(csvSource, ',', ref cols);
            TimeSpan ts2 = DateTime.Now - st;
            Console.WriteLine("Result of csv_remove_unused_data_split: {0}", ts2.TotalMilliseconds);
            Console.WriteLine();
            Console.ReadLine();
        }


        static String csv_remove_unused_data(String input, Char delimiter, ref Boolean[] columns)
        {
            StringBuilder output = new StringBuilder(input.Length);
            int cl = columns.Length;
            Int32 column = 0;
            for (int i = 0; i < input.Length; i++)
            {
                if (input[i] == delimiter)
                {
                    column++;
                    output.Append(input[i]);
                }else{
                    if (column < cl) { if (!columns[column]) output.Append(input[i]); }
                }
            }

            return output.ToString();
        }

        static char[] sep = new char[1];
        static String csv_remove_unused_data_split(String input, Char delimiter, ref Boolean[] columns)
        {

            StringBuilder output = new StringBuilder(input.Length);
            sep[0] = delimiter;
            string[] spl = input.Split(sep);
            if (spl.Length == columns.Length)
            {
                for (int i = 0; i < spl.Length; i++)
                {
                    if (!columns[i]) output.Append(spl[i]);
                    output.Append(delimiter);
                }
            }
            return output.ToString();
        }

    }
}


Результаты весьма интересные...
...
Рейтинг: 0 / 0
03.09.2013, 21:17
    #38385950
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Извините, нагавнял в коде , надо было так:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
using System;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            bool[] cols = new bool[] { false, false, true, false, false, true, true, false, false, true, false, false, true, true, false, true, false, false, false, true, false, false, true, true, false, true, false, true, false, false, false, true, false, false, true, true, false, true, false };
            string csvSource = "11111,22222,33333,44444,55555,66666,77777,88888,943023,1000000000,11111,22222,33333,44444,55555,66666,77777,88888,943023,1000000000,11111,22222,33333,44444,55555,66666,77777,88888,943023,1000000000,11111,22222,33333,44444,55555,66666,77777,88888,943023,1000000000";
            Console.WriteLine(csvSource);
            Console.WriteLine("csv_remove_unused_data");
            DateTime st = DateTime.Now;
            for (int i = 0; i < 10000; i++)
                csv_remove_unused_data(csvSource, ',', ref cols);
            TimeSpan ts = DateTime.Now - st;
            Console.WriteLine("Result of csv_remove_unused_data: {0}", ts.TotalMilliseconds);
            Console.WriteLine();

            Console.WriteLine("csv_remove_unused_data_split");
            st = DateTime.Now;
            for (int i = 0; i < 10000; i++)
                csv_remove_unused_data_split(csvSource, ',', ref cols);// <- Вот здесь в прошлой версии была кака :)))
            TimeSpan ts2 = DateTime.Now - st;
            Console.WriteLine("Result of csv_remove_unused_data_split: {0}", ts2.TotalMilliseconds);
            Console.WriteLine();
            Console.ReadLine();
        }


        static String csv_remove_unused_data(String input, Char delimiter, ref Boolean[] columns)
        {
            StringBuilder output = new StringBuilder(input.Length);
            int cl = columns.Length;
            Int32 column = 0;
            for (int i = 0; i < input.Length; i++)
            {
                if (input[i] == delimiter)
                {
                    column++;
                    output.Append(input[i]);
                }
                else
                {
                    if (column < cl) { if (!columns[column]) output.Append(input[i]); }
                }
            }

            return output.ToString();
        }

        static char[] sep = new char[1];
        static String csv_remove_unused_data_split(String input, Char delimiter, ref Boolean[] columns)
        {

            StringBuilder output = new StringBuilder(input.Length);
            sep[0] = delimiter;
            string[] spl = input.Split(sep);
            if (spl.Length == columns.Length)
            {
                for (int i = 0; i < spl.Length; i++)
                {
                    if (!columns[i]) output.Append(spl[i]);
                    output.Append(delimiter);
                }
            }
            return output.ToString();
        }

    }
}

...
Рейтинг: 0 / 0
03.09.2013, 21:39
    #38385962
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Блин, под вечер что-то я с тестовыми данными напутал.
Вот исправленная версия, в которой больше тестовых данных и итераций:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
using System;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            bool[] cols = new bool[] { false, false, true,  false, false, true, true,  false, false, true, 
                                       false, false, true,  true,  false, true, false, false, false, true, 
                                       false, false, true,  true,  false, true, false, true,  false, false, 
                                       false, true,  false, false, true,  true, false, true,  false, false,
                                       false, false, true,  true,  false, true, false, true,  false, false, 
                                       false, true,  false, false, true,  true, false, true,  false, false
            };
            string csvSource = "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, "+
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, " +
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, " +
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, " +
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, " +
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000";
            Console.WriteLine("csv_remove_unused_data");
            DateTime st = DateTime.Now;
            for (int i = 0; i < 100000; i++)
                csv_remove_unused_data(csvSource, ',', ref cols);
            TimeSpan ts = DateTime.Now - st;
            Console.WriteLine();
            Console.WriteLine("Result of csv_remove_unused_data: {0}", ts.TotalMilliseconds);
            Console.WriteLine();

            Console.WriteLine("csv_remove_unused_data_split");
            st = DateTime.Now;
            for (int i = 0; i < 100000; i++)
                csv_remove_unused_data_split(csvSource, ',', ref cols);
            TimeSpan ts2 = DateTime.Now - st;
            Console.WriteLine();
            Console.WriteLine("Result of csv_remove_unused_data_split: {0}", ts2.TotalMilliseconds);
            Console.ReadLine();
        }


        static String csv_remove_unused_data(String input, Char delimiter, ref Boolean[] columns)
        {
            StringBuilder output = new StringBuilder(input.Length);
            int cl = columns.Length;
            Int32 column = 0;
            for (int i = 0; i < input.Length; i++)
            {
                if (input[i] == delimiter)
                {
                    column++;
                    output.Append(input[i]);
                }
                else
                {
                    if (!columns[column]) output.Append(input[i]);
                }
            }

            return output.ToString();
        }

        static char[] sep = new char[1];
        static String csv_remove_unused_data_split(String input, Char delimiter, ref Boolean[] columns)
        {

            StringBuilder output = new StringBuilder(input.Length);
            sep[0] = delimiter;
            string[] spl = input.Split(sep);
            for (int i = 0; i < spl.Length; i++)
            {
                if (!columns[i]) output.Append(spl[i]);
                if (i < spl.Length - 1) output.Append(delimiter);
            }
            return output.ToString();
        }

    }
}


как видно из тестов, даже не смотря на то, что String.Split, согласно справке является медленной функцией, в таких вещах она гораздо выгодней к использованию.

Есть конечно вариант отказаться от использования string в качестве входного параметра в функцию и передавать ссылку на массив char. Тогда должна по идее отработать быстрее первая версия...
...
Рейтинг: 0 / 0
03.09.2013, 21:57
    #38385973
Alex Kuznetsov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация функции замены строки
Как и ожидал, при смене входного параметра со String на ref char[] прирост в скорости есть, даже по сравнению с версией со Split.


Вот версия программы:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
using System;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            bool[] cols = new bool[] { false, false, true,  false, false, true, true,  false, false, true, 
                                       false, false, true,  true,  false, true, false, false, false, true, 
                                       false, false, true,  true,  false, true, false, true,  false, false, 
                                       false, true,  false, false, true,  true, false, true,  false, false,
                                       false, false, true,  true,  false, true, false, true,  false, false, 
                                       false, true,  false, false, true,  true, false, true,  false, false
            };
            string csvSource = "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, "+
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, " +
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, " +
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, " +
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000, " +
                               "11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 943023, 1000000000";
            int iterations = 100000;

            Console.WriteLine("csv_remove_unused_data_array");
            DateTime st = DateTime.Now;
            char[] carr = null;
            for (int i = 0; i < iterations; i++)
            {
                carr = csvSource.ToCharArray();
                csv_remove_unused_data_array(ref carr, ',', ref cols);
            }
            TimeSpan ts = DateTime.Now - st;
            Console.WriteLine();
            Console.WriteLine("Result of csv_remove_unused_data_array: {0}", ts.TotalMilliseconds);

            Console.WriteLine();
            Console.WriteLine("csv_remove_unused_data_split");
            DateTime st2 = DateTime.Now;
            for (int i = 0; i < iterations; i++)
                csv_remove_unused_data_split(csvSource, ',', ref cols);
            TimeSpan ts2 = DateTime.Now - st2;
            Console.WriteLine();
            Console.WriteLine("Result of csv_remove_unused_data_split: {0}", ts2.TotalMilliseconds);

            Console.WriteLine();
            Console.WriteLine("csv_remove_unused_data");
            DateTime st3 = DateTime.Now;
            for (int i = 0; i < iterations; i++)
                csv_remove_unused_data(csvSource, ',', ref cols);
            TimeSpan ts3 = DateTime.Now - st3;
            Console.WriteLine();
            Console.WriteLine("Result of csv_remove_unused_data: {0}", ts3.TotalMilliseconds);
            
            Console.ReadLine();
        }


        static String csv_remove_unused_data(String input, Char delimiter, ref Boolean[] columns)
        {
            StringBuilder output = new StringBuilder(input.Length);
            int cl = columns.Length;
            Int32 column = 0;
            for (int i = 0; i < input.Length; i++)
            {
                if (input[i] == delimiter)
                {
                    column++;
                    output.Append(input[i]);
                }
                else
                {
                    if (!columns[column]) output.Append(input[i]);
                }
            }

            return output.ToString();
        }

        static String csv_remove_unused_data_array(ref char[] input, Char delimiter, ref Boolean[] columns)
        {
            StringBuilder output = new StringBuilder(input.Length);
            int cl = columns.Length;
            Int32 column = 0;
            for (int i = 0; i < input.Length; i++)
            {
                if (input[i] == delimiter)
                {
                    column++;
                    output.Append(input[i]);
                }
                else
                {
                    if (!columns[column]) output.Append(input[i]);
                }
            }

            return output.ToString();
        }

        static char[] sep = new char[1];
        static String csv_remove_unused_data_split(String input, Char delimiter, ref Boolean[] columns)
        {

            StringBuilder output = new StringBuilder(input.Length);
            sep[0] = delimiter;
            string[] spl = input.Split(sep);
            for (int i = 0; i < spl.Length; i++)
            {
                if (!columns[i]) output.Append(spl[i]);
                if (i < spl.Length - 1) output.Append(delimiter);
            }
            return output.ToString();
        }

    }
}


Ну, и конечно же результат:
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Оптимизация функции замены строки / 14 сообщений из 14, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]