Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.50/2: Рейтинг темы: голосов - 2, средняя оценка - 4.50
a.n.o.n.i.m
137 / 137 / 39
Регистрация: 26.02.2011
Сообщений: 543
1

Как заставить функцию работать быстрее?

26.09.2016, 08:11. Просмотров 477. Ответов 11
Метки нет (Все метки)

Может кто подсказать в плане оптимизации как заставить функцию Check() работать быстрее? Применил StringBilder вместо string, код стал работать в 3 раза быстрее. Может кто еще каких идей подкинет?

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
 
namespace PA_Hard
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            button1.Enabled = false;
            Form1.CheckForIllegalCrossThreadCalls = false;
        }
 
        static bool flag = true;
        string alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        int length_pass = 1;
        StringBuilder pass = new StringBuilder();
 
        public void Check()
        {
            ulong number_of_combinations = 0;
            Stopwatch st = new Stopwatch();
            st.Start();
            while (flag)
            {
                StringBuilder result = new StringBuilder();
                int[] index = new int[length_pass];
                bool finish = true;
                while (finish)
                {
                    number_of_combinations++;
                    for (int i = 0; i < index.Length; i++)
                    {
                        result.Append(alphabet[index[i]]);
                    }
                    if (result.Equals(pass))
                    {
                        flag = false;
                        st.Stop();
                        richTextBox1.Text = "Пароль " + result + "\nПодобран с " + number_of_combinations.ToString() + " комбинации\nВремя затрачено " + st.Elapsed.TotalSeconds.ToString();
                        break;
                    }
                    result.Clear();
                    index[index.Length - 1]++;                        
                    for (int i = (index.Length - 1); i >= 0; i--)
                    {
                        if (index[i] > (alphabet.Length - 1))             
                        {
                            index[i] = 0;                              
                            if (--i < 0)
                            {
                                finish = false;
                                break;
                            }
                            index[i]++;                               
                            i++;
                        }
                    }
                }
                length_pass++;
            }
            flag = true;
            length_pass = 1;
            number_of_combinations = 0;
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            Thread ChechThread = new Thread(Check);
            ChechThread.IsBackground = true;
            ChechThread.Start();
        }
 
        private void textBox1_TextChanged(object sender, EventArgs e)//Проверочка на корректный ввод
        {
            int i = 0;
            try
            {
                if (textBox1.Text[i] != null)// Попробую вызвать исключение с индексом 
                {
                    i++;
                }
            }
            catch (IndexOutOfRangeException)
            {
                //break; //ничего не ввели в поле
            }
            if (i > 0)
            {
                i = 0;
                pass.Clear();
                while (true)
                {
                    try
                    {
                        if ((Convert.ToInt32(textBox1.Text[i]) >= 48 && Convert.ToInt32(textBox1.Text[i]) <= 57) ||
                            (Convert.ToInt32(textBox1.Text[i]) >= 65 && Convert.ToInt32(textBox1.Text[i]) <= 90) ||
                            (Convert.ToInt32(textBox1.Text[i]) >= 97 && Convert.ToInt32(textBox1.Text[i]) <= 122))
                        {
                            button1.Enabled = true;
                            pass.Append(textBox1.Text[i]);
                            richTextBox1.Text = "Пароль задан верно\n";
                        }
                        else
                        {
                            button1.Enabled = false;
                            richTextBox1.Text = "Присутстуют неккоректные символы\n";
                            break;
                        }
                        i++;
                    }
                    catch (IndexOutOfRangeException)
                    {
                        break;
                    }
                }
            }
            else
            {
                button1.Enabled = false;
                richTextBox1.Text = "Введите хотя бы один символ\n";
            }
        }
    }
}
Добавлено через 15 часов 57 минут
форум умер.
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.09.2016, 08:11
Ответы с готовыми решениями:

Как заставить программу работать постоянно?
Здравствуйте! Мне нужно сделать так, что бы программа работала постоянно. Я уже попытался...

как заставить работать событие gridView_DoubleClick
private void gridView6_DoubleClick(object sender, System.EventHandler e) { ...

Как заставить Socket работать и с IPv4, и с IPv6?
Доброе время суток! Подскажите, как заставить Socket работать с обеими вариантами IP одновременно?...

Очистка памяти, как заставить работать дворника
уже неделю пытаюсь разобраться в очистке памяти но все как то поверхностно... по этому прошу...

Разные проекты в одном solution - как заставить работать?
Есть основной проект - Windows Application(C#) и ещё один - Console Application(C). Нужно...

11
wastegate
9 / 9 / 2
Регистрация: 10.04.2015
Сообщений: 37
26.09.2016, 11:38 2
циклы FOR дают основную задержку выполняй их параллельно.
0
BroDMax
155 / 154 / 104
Регистрация: 01.10.2015
Сообщений: 310
26.09.2016, 12:28 3
a.n.o.n.i.m, здравствуйте. Начнем обычный анализ:
  1. Для начала, компилятор ругается на эту строку:
    C#
    1
    
    if (textBox1.Text[i] != null)
    Пишет, что Результат выражения всегда равен true, поскольку значение типа "int" никогда не равно Null типа "int?". Что Вы хотели сделать этим? Проверить поле ввода на пустое значение? Тогда воспользуйтесь банальной проверкой, не нужно лепить try/cath, они тяжело обрабатываются процессором:
    C#
    1
    
    if (string.IsNullOrWhiteSpace(textBox1.Text))
  2. Далее, в цикле while Вы снова поставили try/catch. Мы всегда знаем размер поля, иначе быть не может. Поэтому воспользуемся свойством Length.
  3. C#
    1
    2
    3
    
    if ((Convert.ToInt32(textBox1.Text[i]) >= 48 && Convert.ToInt32(textBox1.Text[i]) <= 57) ||
        (Convert.ToInt32(textBox1.Text[i]) >= 65 && Convert.ToInt32(textBox1.Text[i]) <= 90) ||
        (Convert.ToInt32(textBox1.Text[i]) >= 97 && Convert.ToInt32(textBox1.Text[i]) <= 122))
    Конвертируете аж 6 раз подряд одно и то же (!). Сделайте это один раз.

НО это все понятно Вы же сюда пришли за оптимизацией функции Check(), не так ли? Тогда вот, чуть-чуть подправил. По моим скромным подсчетам, выполнение кода ускорено примерно на 27%. Вот весь код:
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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
 
namespace PA_Hard
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            button1.Enabled = false;
            Form1.CheckForIllegalCrossThreadCalls = false;
        }
 
        string alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        StringBuilder pass = new StringBuilder();
 
        public void Check()
        {
            ulong number_of_combinations = 0;
            int length_pass = 1;
            StringBuilder result = new StringBuilder();
            Stopwatch st = new Stopwatch();
            st.Start();
            while (true)
            {
                result.Clear();
                int[] index = new int[length_pass];
                int LEN = length_pass - 1;
                int LEN_ABC = alphabet.Length - 1;
                while (true)
                {
                    number_of_combinations++;
                    for (int i = 0; i < length_pass; i++)
                    {
                        result.Append(alphabet[index[i]]);
                    }
                    if (result.Equals(pass))
                    {
                        st.Stop();
                        richTextBox1.Text = "Пароль " + result + "\nПодобран с " + number_of_combinations.ToString() + " комбинации\nВремя затрачено " + st.Elapsed.TotalSeconds.ToString();
                        return;
                    }
                    result.Clear();
                    index[LEN]++;
                    for (int i = LEN; i > 0; i--)
                    {
                        if (index[i] > LEN_ABC)
                        {
                            index[i] = 0;
                            index[i - 1]++;
                        }
                    }
                    //
                    if (index[0] > LEN_ABC)
                    {
                        index[0] = 0;
                        break;
                    }
                    //
                }
                length_pass++;
            }
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            Thread ChechThread = new Thread(Check);
            ChechThread.IsBackground = true;
            ChechThread.Start();
        }
 
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(textBox1.Text))
            {
                button1.Enabled = false;
                richTextBox1.Text = "Введите хотя бы один символ\n";
                return;
            }
            pass.Clear();
 
            for (int i = 0; i < textBox1.Text.Length; i++)
            {
                int Num = Convert.ToInt32(textBox1.Text[i]);
 
                if ((Num > 47 && Num < 58) || // Цифры
                    (Num > 64 && Num < 91) || // Прописные
                    (Num > 96 && Num < 123))   // Строчные
                {
                    button1.Enabled = true;
                    pass.Append(textBox1.Text[i]);
                    richTextBox1.Text = "Пароль задан верно\n";
                }
                else
                {
                    button1.Enabled = false;
                    richTextBox1.Text = "Присутстуют неккоректные символы\n";
                    break;
                }
            }
        }
    }
}
1
a.n.o.n.i.m
137 / 137 / 39
Регистрация: 26.02.2011
Сообщений: 543
26.09.2016, 13:57  [ТС] 4
Спасибо за ответ. Ща перепроверим все это.

РАЗМЕР ПОЛЯ МЫ НЕ ЗНАЕМ. Ленгтх не нужно тут. Свои тараканы вообщем.
Проверку трогать не нужно, она выполняется мало раз все равно, не как не скажется на быстродействии

C#
1
if (textBox1.Text[i] != null)
Это уже моя идея, ее не нужно трогать, она проверить есть ли хотя бы один символ в текстбоксе, обратившись к индексу и не вызвав исключение при этом, там от балды проверка. Нужно тупо обратиться было к индексу.


И это я жду фишки типа Стринг поменять на Стрингбилдер, может еще че такое же сможете подсказать.
0
26.09.2016, 13:57
Usaga
Эксперт .NET
6192 / 4405 / 767
Регистрация: 21.01.2016
Сообщений: 17,168
Завершенные тесты: 2
26.09.2016, 14:01 5
a.n.o.n.i.m, тебе намекнули, что вот это if (textBox1.Text[i] != null) не имеет смысла, так как контрол всегда будет возвращать строку (если контрол пуст, то и строка будет пуста, но она не будет null).

Добавлено через 32 секунды
Т.е. это не медленно, это - тупо ошибка.
0
a.n.o.n.i.m
137 / 137 / 39
Регистрация: 26.02.2011
Сообщений: 543
26.09.2016, 14:43  [ТС] 6
Да это условие тупо заглушка(мне тупо к индексу обратиться и все, пустое ничего не значимое условие), ребят не на то внимание. Заставить Check() работать быстрее, идеи интересно послушать, а остальное не смотрите.

Добавлено через 6 минут
Блин точно, зачем мне каждый раз вычислять в форе значение (index.Length - 1) и в условии (alphabet.Length - 1) тоже, можно же при входи 1 раз их вычеслить и все, ну это в вашем примере и сделано. Изза этого я так понял удалось ускорить процесс верно?
0
BroDMax
155 / 154 / 104
Регистрация: 01.10.2015
Сообщений: 310
26.09.2016, 17:20 7
Цитата Сообщение от a.n.o.n.i.m Посмотреть сообщение
Изза этого я так понял удалось ускорить процесс верно?
Не совсем так.
Такая оптимизация не столь существенна. Ускорить процесс удалось благодаря удалению условия из цикла вот здесь:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (int i = (index.Length - 1); i >= 0; i--)
{
    if (index[i] > (alphabet.Length - 1))
    {
        index[i] = 0;
        if (--i < 0)
        {
            finish = false;
            break;
        }
        index[i]++;
        i++;
    }
}
Поясняю: На КАЖДОЙ итерации мы заставляем процессор проверить, достигла ли переменная i нуля? Условия для процессора не такие уж и маленькие, да еще и на каждой итерации цикла выполняем их! Убрать просто так условие не получится, потому что Вы это сделали специально, чтобы не получилось обращение к массиву index с индексом -1, так как у нее сначала отнимается единица вот здесь:if (--i < 0) Поэтому было принято решение убрать проверку на нулевой индекс и просто сделать цикл до единицы (то есть все элементы БОЛЬШЕ нуля):
C#
1
2
3
4
5
6
7
8
for (int i = LEN; i > 0; i--)
{
    if (index[i] > LEN_ABC)
    {
        index[i] = 0;
        index[i - 1]++;
    }
}
И еще: у Вас получилось так, что пришлось сначала отнимать у переменной i единицу, прибавлять единицу к значению и снова возвращать переменной i единицу. Тогда как я сделал просто (i - 1), сохранив само значение индекса, и при этом прибавил единицу к значению. Я, надеюсь, выражаюсь понятным языком

Теперь в цикле выполняется всего одно условие вместо двух.

Что же теперь делать с нулевым значением? Обработаем его отдельно, вот и все. Мы точно знаем, что все элементы были обработаны, кроме самого первого – нулевого. Поэтому создаем отдельный блок кода для обработки первого элемента (единожды, без циклов):
C#
1
2
3
4
5
if (index[0] > LEN_ABC)
{
    index[0] = 0;
    break;
}
Насчет остального, что было сделано в коде повторюсь – это не значительные изменения. Но все же они чуть-чуть ускоряют процесс. Естественно, я удалил ненужные переменные и выставил бесконечные циклы. Лишние действия тоже не нужны.
1
a.n.o.n.i.m
137 / 137 / 39
Регистрация: 26.02.2011
Сообщений: 543
26.09.2016, 20:26  [ТС] 8
Когда в процессе много выч.операций , играет роль каждая мелоч. Чисто (index.Length - 1) и (alphabet.Length - 1) просто из первого поста , проведя эксперимент, производительность сразу выросла на 15-20% , это довольно неплохо. С лишними условиями - да беда,но и это было придумать не так уж и просто. Спасибо за интересные замечания, продолжаю дальше копать....

Добавлено через 1 час 30 минут
В принцыпе этот if с нулем можно было не выносить, так как мы в него не попадем, пока не попадем в первый, а это довольно мало раз. Так что его если вынести или оставить внутри другого if не придаст производительности

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
if (index[i] > alphabet_length_1)
                            {
                                if (i > 0)
                                {
                                    index[i] = 0;
                                    index[i - 1]++;
                                }
                                else
                                {
                                    finish = false;
                                    break;
                                }
                            }
А вот насчет конструкции

C#
1
index[i - 1]++;
это должно придать, Почему? потому что 1) Мы сдвинулись назад 2) изменили значение 3) сдвинулись вперед. А так получается из кода строчки выше мы 1) Посчитали i-1 2) Изменили значение. Тоесть выходит на одну операции меньше делать. А это какая никакая тоже польза в быстродействии

C#
1
2
3
                    --i;
                                index[i]++;
                                i++;
0
Usaga
Эксперт .NET
6192 / 4405 / 767
Регистрация: 21.01.2016
Сообщений: 17,168
Завершенные тесты: 2
27.09.2016, 06:59 9
a.n.o.n.i.m, может распараллеливание даст прирост к скорости вычислений:

Кликните здесь для просмотра всего текста

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        string alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        StringBuilder pass = new StringBuilder();
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private async void button1_Click(object sender, EventArgs e)
        {
            var context = SynchronizationContext.Current;
            await Task.Run(() => Check(context));
        }
 
        public void Check(SynchronizationContext context)
        {
            Stopwatch st = new Stopwatch();
            st.Start();
            int LEN_ABC = alphabet.Length - 1;
            int combinationsCounter = 0;
            int passLength = 0;
 
            Parallel.For(1, 100, new ParallelOptions {MaxDegreeOfParallelism = 3} , (_p, loopState) =>
            {
                StringBuilder result = new StringBuilder();
                int length_pass = Interlocked.Increment(ref passLength);
                int[] index = new int[length_pass];
                int LEN = length_pass - 1;
 
                while (!loopState.IsStopped) {
                    int combination = Interlocked.Increment(ref combinationsCounter);
 
                    for (int i = 0; i < length_pass; i++) {
                        result.Append(alphabet[index[i]]);
                    }
                    if (result.Equals(pass)) {
                        st.Stop();
                        context.Post((_) =>
                        {
                            mainLabel.Text = "Пароль " + result + "\nПодобран с " +
                                             combination + " комбинации\nВремя затрачено " +
                                             st.Elapsed.TotalSeconds.ToString();
                        }, null);
                        loopState.Stop();
                        break;
                    }
                    result.Clear();
                    index[LEN]++;
                    for (int i = LEN; i > 0; i--) {
                        if (index[i] > LEN_ABC) {
                            index[i] = 0;
                            index[i - 1]++;
                        }
                    }
                        //
                        if (index[0] > LEN_ABC) {
                        index[0] = 0;
                        break;
                    }
                }
            });
        }
 
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(textBox1.Text)) {
                button1.Enabled = false;
                mainLabel.Text = "Введите хотя бы один символ\n";
                return;
            }
            pass.Clear();
 
            for (int i = 0; i < textBox1.Text.Length; i++) {
                int Num = Convert.ToInt32(textBox1.Text[i]);
 
                if ((Num > 47 && Num < 58) || // Цифры
                    (Num > 64 && Num < 91) || // Прописные
                    (Num > 96 && Num < 123))   // Строчные
                {
                    button1.Enabled = true;
                    pass.Append(textBox1.Text[i]);
                    mainLabel.Text = "Пароль задан верно\n";
                } else {
                    button1.Enabled = false;
                    mainLabel.Text = "Присутстуют неккоректные символы\n";
                    break;
                }
            }
        }
    }
}


Добавлено через 7 минут
По хорошему, тут нужно избавиться от StringBuilder. Нужно завести массив байт, куда сложить байты пароля, сделать копию для каждого потока (чтобы не было false sharing) и сравнивать байты с комбинацией получаемой в потоке (тоже массив байт). И счётчик комбинации тоже в каждом потоке свой должен быть. Вот тогда будет по настоящему быстро
1
a.n.o.n.i.m
137 / 137 / 39
Регистрация: 26.02.2011
Сообщений: 543
27.09.2016, 16:48  [ТС] 10
Я считал своим главным открытием StringBuilder в плане быстродействия)) А распараллеливание как раз разжёвываю сейчас сижу, ибо в статьях которые читаю, дает хороший прирост к скорости, а мне вообще любая даже мелочь важна. Вообще была мысль про GPU почитать, но это уже сторонние библиотеки подключать, не то, хотя там то да, судя по прочитанным мною проведенным экспериментам, скорость сразу в раз 100 подымаеца. Спасибо за инфу, расшарю это дело)

Добавлено через 18 минут
Так, распаралеливание скорости не дало, еще в 4 раза медленнее стало. Копаю дальше.
0
BroDMax
155 / 154 / 104
Регистрация: 01.10.2015
Сообщений: 310
27.09.2016, 16:56 11
Цитата Сообщение от Usaga Посмотреть сообщение
Нужно завести массив байт
a.n.o.n.i.m, вот это самое мудрое решение. Но на C# это нужно делать через IntPtr и Marshal. Вам лучше подойдет C++.
И не использовать Unicode, так как у Вас ограниченные символы, которые можно представить в однобайтовой кодировке.
1
a.n.o.n.i.m
137 / 137 / 39
Регистрация: 26.02.2011
Сообщений: 543
27.09.2016, 19:43  [ТС] 12
Спасибо за мысль, изучим это дело.
0
27.09.2016, 19:43
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
27.09.2016, 19:43

Как заставить программу работать при старте системы?
Здравствуйте! Сразу скажу что я уже пытался закинуть программу в автозагрузку как просто -...

Как заставить exe приложение работать файлом из ресурса?
мой exe приложения через OpenFileDialog работает но надо чтоб работаль Файлом из ресурса пример ...

Как заставить программу работать вечно, без пожирания ресурсов?
как я понимаю на это способны службы, но как консольное приложение превратить в службу?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.