Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.80/75: Рейтинг темы: голосов - 75, средняя оценка - 4.80
14 / 4 / 1
Регистрация: 08.11.2012
Сообщений: 189
Записей в блоге: 1
.NET 4.x

Зависание программы при выполнении длительного цикла

26.01.2015, 16:26. Показов 16409. Ответов 27
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
В моей программе выполняется долго, очень долго цикл, так как много данных обрабатывается.
Программа работает и отрабатывает цикл нормально.
Но на время выполнения цикла, программа как бы зависает.
Как это происходит.
Если переключиться на другую программу, а потом вернуться, то в тайтле программы добавляется текст "Не отвечает" и при клике на программу она покрывается белым фоном.
Такое состояние до момента завершения цикла, после чего программа возвращается в нормальное состояние и в цикле все выполнено правильно.

У меня стоит задача убрать именно это неприятное явление, а не исправлять код, так как код работает хорошо.
Я пробовал выводить цикл в отдельный поток через BackgroundWorker, но ничего не меняется.

Пробовал также добавлять в каждый шаг итерации цикла Application.DoEvents();, но также не помогает.

Какие еще есть варианты?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.01.2015, 16:26
Ответы с готовыми решениями:

Зависание формы при выполнении цикла
Есть бот который выполняет get запросы каждые 30 секунд. Запрос находится в исключении, а исключение в цикле. Так вот, когда выполняется...

Постепенное выполнение программы/зависание программы при выполнении
Собственно есть вопрос, возможно очень даже глупый, но все же спрошу: почему при выполнении большого кол-ва операций программа повисает, а...

При выполнении кода, полное зависание программы
Private Sub Кнопка2_Click() Dim x As Integer, i As Integer Dim a As Double, W As Double a = 2.5 For i = 1 To 5 Step 0.5 If...

27
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
09.03.2015, 00:29
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Vitukr Посмотреть сообщение
4 ядра.
Тогда проблема явно в коде. Например, вы вызваете Invoke в обработчике ProgressChanged ?

Добавлено через 5 минут
Вот пример, все работает, прогресс бар бежит, без Sleep:
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
using System;
using System.ComponentModel;
using System.Windows.Forms;
 
namespace WindowsFormsApplication258
{
    public partial class Form1 : Form
    {
        private ProgressBar pb;
        private BackgroundWorker bw;
 
        public Form1()
        {
            InitializeComponent();
 
            pb = new ProgressBar() {Parent = this, Maximum = 100, Minimum = 0};
 
            bw = new BackgroundWorker(){WorkerReportsProgress = true};
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerAsync();
        }
 
        void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Invoke((Action)(()=>pb.Value = e.ProgressPercentage));
        }
 
        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i < 20000; i++)
            {
                var s = "";
                for (int j = 0; j < 300; j++)
                    s += j.ToString();
                bw.ReportProgress(i*100/20000);
            }
        }
    }
}
0
14 / 4 / 1
Регистрация: 08.11.2012
Сообщений: 189
Записей в блоге: 1
09.03.2015, 00:32  [ТС]
Это не мой код, это код который идет как экспертный с рекомендацией Майкрософт.
Если посмотреть МСДН, то вроде все правильно.
Должно работать. И оно работает, но только с "засыпание".
А без "засыпания" ни один экспертный пример не работает.
Вот в чем интерес.
Другими словами, я что хочу сказать: может изначально этот BackgroundWorker не правильно создан Майкрософтом? Так как без засыпания не работает.
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
09.03.2015, 00:34
Цитата Сообщение от Vitukr Посмотреть сообщение
Так как без засыпания не работает.
Пример выше работает и без засыпания.

Цитата Сообщение от Vitukr Посмотреть сообщение
А без "засыпания" ни один экспертный пример не работает.
Привидите конкретный код, посмотрим.
0
14 / 4 / 1
Регистрация: 08.11.2012
Сообщений: 189
Записей в блоге: 1
09.03.2015, 00:48  [ТС]
Я уже писал выше, что сейчас пример на WPF приложении, а тему начинал на WindowsForms.
Поэтому код приведу на WPF.
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Window x:Class="Wpf_test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cm="clr-namespace:System.ComponentModel;assembly=System"
        Title="MainWindow" Height="350" Width="525" WindowStartupLocation="CenterScreen">
    
 
    <Grid x:Name="MyGrid">
        
        <ProgressBar x:Name="workerProgress" HorizontalAlignment="Left" Height="42" Margin="10,81,0,0" VerticalAlignment="Top" Width="497" Value="0" Minimum="0" Maximum="100"/>
        <TextBox x:Name="inputBox" HorizontalAlignment="Left" Height="23" Margin="222,31,0,0" TextWrapping="Wrap" Text="10000" VerticalAlignment="Top" Width="120"/>
        <TextBox x:Name="outputBox" HorizontalAlignment="Left" Height="23" Margin="222,201,0,0" TextWrapping="Wrap" Text="0" VerticalAlignment="Top" Width="120"/>
        <Button x:Name="startButton" Content="Start" HorizontalAlignment="Left" Margin="115,256,0,0" VerticalAlignment="Top" Width="75" Click="startButton_Click"  >
        </Button>
        <Button x:Name="cancelButton" Content="Cancel" HorizontalAlignment="Left" Margin="257,256,0,0" VerticalAlignment="Top" Width="75" Click="cancelButton_Click"/>
        <Label Content="Iterations" HorizontalAlignment="Left" Margin="115,29,0,0" VerticalAlignment="Top"/>
        <Label Content="Output" HorizontalAlignment="Left" Margin="115,199,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.421,-0.538"/>
 
    </Grid>
</Window>
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
 
using System.ComponentModel;
using System.Threading;
 
namespace Wpf_test
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>    /// 
    public partial class MainWindow : Window
    {
        private BackgroundWorker backgroundWorker;
        private Count_bar cb;
        
        public MainWindow()
        {
            InitializeComponent();
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += backgroundWorker_DoWork;
            backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
            backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.WorkerSupportsCancellation = true;
        }
 
        void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                outputBox.Text = "Canceled";
            }
            else
            {
                outputBox.Text = e.Result.ToString();
                workerProgress.Value = 0;
            }
            startButton.IsEnabled = true;
            cancelButton.IsEnabled = false;
        }
 
        void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var bgw = sender as BackgroundWorker;
            workerProgress.Value = e.ProgressPercentage;
            outputBox.Text = (e.UserState as Count_bar).num.ToString() + " : " + e.ProgressPercentage.ToString() + "%";
        }
 
        void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var bgw = sender as BackgroundWorker;
            e.Result = DoSlowProcess((Count_bar)e.Argument, bgw, e);
        }
 
        private int DoSlowProcess(Count_bar cb, BackgroundWorker worker, DoWorkEventArgs e)
        {
            Count_bar ncb = new Count_bar();
            int result = 0;
            for (int i = 0; i <= cb.num; i++)
            {
                if (worker != null)
                {
                    if (worker.CancellationPending)
                    {
                        e.Cancel = true;
                        return result;
                    }
                    if (worker.WorkerReportsProgress)
                    {
                        ncb.num = i * 10;
                        int percentComplete =
                        (int)((float)i / (float)cb.num * 100);
                        worker.ReportProgress(percentComplete, ncb);
                    }
                }
                //Thread.Sleep(1);
                result = i;
            }
            return result;
        }     
 
        private void startButton_Click(object sender, RoutedEventArgs e)
        {
            int iterations = 0;
            if (int.TryParse(inputBox.Text, out iterations))
            {
                cb = new Count_bar();
                cb.num = iterations;
                startButton.IsEnabled = false;
                cancelButton.IsEnabled = true;
                outputBox.Text = "";
                backgroundWorker.RunWorkerAsync(cb);
            }
        }
 
        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.backgroundWorker.CancelAsync();
        }
    }
}
Можно ли здесь применить Инвоук?

Добавлено через 3 минуты
Также, можно по этой ссылке скачать на странице весь код проекта:
http://outcoldman.com/ru/archi... %BA%D0%B5/
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
09.03.2015, 01:34
Цитата Сообщение от Vitukr Посмотреть сообщение
Можно ли здесь применить Инвоук?
Можно и нужно.

Добавлено через 1 минуту
C#
1
2
3
4
5
6
7
8
9
10
        void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var percent = e.ProgressPercentage;
            
            this.Dispatcher.Invoke((Action)(()=>
            {
                workerProgress.Value = percent;
                outputBox.Text = (e.UserState as Count_bar).num.ToString() + " : " + percent.ToString() + "%";
            }));
        }
Добавлено через 7 минут
Но и этого не достаточно.
Дело в том, что если вы сейчас запустите этот пример, с Dispatcher.Invoke - интерфейс тоже обновляться скорее всего не будет.
И вот почему. Когда вы вызываете Invoke, в очередь сообщений добавляются команды. Главный поток обрабатывает сообщения и обновляет интерфейс окна. Но вы вызываете Dispatcher.Invoke так часто, что главный поток просто не успевает отрисовать интерфейс, все его время уходит на обработку сообщений, которые вы ему посылаете через Invoke. Поэтому интерфейс висит.
В WinForms такая ситуация разруливается, но в WPF - нет. Я не знаю почему, я не особый спец в WPF.
Пэтому, вам нужно вызывать событие ProgressChanged немного реже, что бы главный паоток успевал обработать очередь сообщений.

Вот пример вашего цикла. Здесь осовное время крутится внутри вложенного цикла. И только после выхода из вложенного цикла - вызывается ProgressChanged:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
        private int DoSlowProcess(Count_bar cb, BackgroundWorker worker, DoWorkEventArgs e)
        {
            Count_bar ncb = new Count_bar();
            int result = 0;
            for (int i = 0; i <= cb.num; i++)
            {
                var s = "";
                for (int j = 0; j < 1400; j++)
                    s += j.ToString();
 
                if (worker.WorkerReportsProgress)
                {
                    ncb.num = i * 10;
                    int percentComplete = i * 100 / cb.num;
                    worker.ReportProgress(percentComplete, ncb);
                }
                //Thread.Sleep(1);
                result = i;
            }
            return result;
        }
Теперь все работает, прогрессбар бежит, Sleep не вызывается.
1
14 / 4 / 1
Регистрация: 08.11.2012
Сообщений: 189
Записей в блоге: 1
09.03.2015, 11:10  [ТС]
Storm23,
К сожалению, вопрос не в Invoke.
Я проверил на WindowsForms и на WPF.
Проблема заключается, как Вы правильно обнаружили, в определенном количестве времени, которое затрачивается на прохождение одной итерации в цикле до вызова ProgressChanged для обновления интефейса основного потока.
Т.е. Thread.Sleep(1); просто необходим был, чтобы сделать задержку на не менее минимальное время для срабатывания ProgressChanged.
Я поставил Ваш дополнительный цикл вместо Thread.Sleep(1); и все работает, даже без Invoke.
Даже так все работает, если дать достаточное время на обновление интерфейса.
C#
1
2
3
4
5
6
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var percent = e.ProgressPercentage;
            workerProgress.Value = percent;
            outputBox.Text = (e.UserState as Count_bar).num.ToString() + " : " + percent.ToString() + "%";
        }
И соответственно в цикле:
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
private int DoSlowProcess(Count_bar cb, BackgroundWorker worker, DoWorkEventArgs e)
        {
            Count_bar ncb = new Count_bar();
            int result = 0;
            for (int i = 0; i <= cb.num; i++)
            {
                //var s = "";
                //for (int j = 0; j < 1000; j++)
                //    s = j.ToString();
 
                if (worker != null)
                {
                    if (worker.CancellationPending)
                    {
                        e.Cancel = true;
                        return result;
                    }
                    if (worker.WorkerReportsProgress)
                    {
                        ncb.num = i * 10;
                        int percentComplete = i * 100 / cb.num;
                        worker.ReportProgress(percentComplete, ncb);
                    }
                }
                var s = "";
                for (int j = 0; j < 1000; j++)
                    s = j.ToString();
                //Thread.Sleep(1);
                result = i;
            }
            return result;
        }
Теперь задача - как определить то минимальное время для срабатывания?
1 миллисекунды явно много.
0
Администратор
Эксперт .NET
 Аватар для OwenGlendower
18344 / 14270 / 5370
Регистрация: 17.03.2014
Сообщений: 28,944
Записей в блоге: 1
09.03.2015, 12:58
Цитата Сообщение от Vitukr Посмотреть сообщение
Теперь задача - как определить то минимальное время для срабатывания?
Вместо поиска этого интервала, которое всё равно будет разным на разных системах, вызывай ReportProgress как можно реже. Например, с шагом 5 процентов.
0
14 / 4 / 1
Регистрация: 08.11.2012
Сообщений: 189
Записей в блоге: 1
09.03.2015, 23:15  [ТС]
Цитата Сообщение от OwenGlendower Посмотреть сообщение
Вместо поиска этого интервала, которое всё равно будет разным на разных системах, вызывай ReportProgress как можно реже. Например, с шагом 5 процентов.
Если говорить о 5%, то это совершенно неприемлемо. Это ж какие скачки будут в прогрессбаре?

Решение я уже нашел. Подсчитывается время, которое затрачивается на одну итерацию, если оно меньше определенного, то дополнительным циклом ждем эту разницу во времени.
Таким образом достигается максимальная производительность и кооректное отображение прогрессбара.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
09.03.2015, 23:15

Чувствительность программы во время длительного цикла
И снова вынужден обратиться к вам за помощью. Есть такая ситуация: for (int i=0;i&lt;индекс;i++){ некое действие ... label1.text =...

Ошибка программы при выполнении цикла перебора
Добрый день коллеги ))) Помогите разобраться. При выполнении процедуры - цикла перебора комбинаций чисел по условию выдает ошибку...

Резкое зависание программы при частом запуске цикла
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls,...

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

Зависание интерфейса при выполнении запроса
Всем привет. Проблема в следующем. Есть кнопка, по ее нажатию отрабатывается запрос к базе данных. Понятно что пока не пришел результат...


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

Или воспользуйтесь поиском по форуму:
28
Ответ Создать тему
Новые блоги и статьи
Текстовый слайдер с нумерацией страниц и кроссбраузерность.
russiannick 18.07.2026
Один мой друг написал текстовый слайдер с нумерацией страниц. Сегодня я расскажу как он умудрился подружить его с кроссбраузерностью. Очевидно сложно угодить с шириной каждому браузеру. Один крадет. . .
Грибы - это мемы, дерево - это человек. Применение микоризной модели к теории меметики Докинза.
anaschu 18.07.2026
Меметический изоморфизм теории «всего»: Грибная сукцессия как модель эволюции идей Докинза Базовый код системы ОДУ микоризной сукцессии описывает не просто биологию, а универсальную. . .
Грибы - это корпорации, деревья - это государства. Механизм массонского захвата власти
anaschu 18.07.2026
Макроэкономический изоморфизм теории «всего»: Грибная сукцессия как модель транснационального капитализма Базовый код системы ОДУ микоризной сукцессии описывает не просто биологию, а. . .
Расчёт периметра прямоугольника по координатам вершин
Maks 18.07.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Вычислить периметр прямоугольника, заданного координатами своих вершин на плоскости. Решение: Создан документ со следующими. . .
Подсчёт частоты трёхбуквенных слов в тексте
Maks 18.07.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Выясните, сколько раз в предложенном тексте встречается каждое трехбуквенное слово. Решение: Создан документ с единственным. . .
Сумма и количество положительных элементов в чётных строках массива
Maks 18.07.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Вычислить сумму и количество положительных элементов массива, расположенных в четных строках. Решение: Создан документ с. . .
Поиск произведения положительных чётных чисел в последовательности
Maks 18.07.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Дана произвольная последовательность целых чисел. Найти произведение положительных четных чисел данной последовательности. . . .
Обработка трёх чисел: утроение и возведение в степень
Maks 18.07.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Даны три действительных числа. Утроить те из них, значения которых неотрицательны, и возвести в четвертую степень отрицательные. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru