Оптимизация кода программы
От: nettro  
Дата: 02.04.12 12:55
Оценка:
Доброго времени суток!
Проблема в следующем: написал программу на c#, которая опрашивает сеть на наличие пингующихся компьютеров в сети, и если компьютер пингуется, ему посылаются wmi запросы по сбору информации о его конфигурации (пока собирается инфа о процессоре, памяти, хардах и видеоадаптере) и всё это дело выводиться в richTextBox (планируется записывать всё это дело в базу, но пока по этому поводу не думал). Так вот, если в сети доступны компов 30, то данная операция опроса выполняется минут 5 и при выполнении форма программы просто зависает и с ней ничего нельзя сделать...
Помогите пожалуйста решить эту проблему, что бы уменьшить время выполнения программы и главное что бы программа не подвисала?

p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.

Спасибо!
visual studio c#
Re: Оптимизация кода программы
От: Glas  
Дата: 02.04.12 13:27
Оценка:
Здравствуйте, nettro, Вы писали:

N>Доброго времени суток!

N>Проблема в следующем: написал программу на c#, которая опрашивает сеть на наличие пингующихся компьютеров в сети, и если компьютер пингуется, ему посылаются wmi запросы по сбору информации о его конфигурации (пока собирается инфа о процессоре, памяти, хардах и видеоадаптере) и всё это дело выводиться в richTextBox (планируется записывать всё это дело в базу, но пока по этому поводу не думал). Так вот, если в сети доступны компов 30, то данная операция опроса выполняется минут 5 и при выполнении форма программы просто зависает и с ней ничего нельзя сделать...
N>Помогите пожалуйста решить эту проблему, что бы уменьшить время выполнения программы и главное что бы программа не подвисала?

N>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.


N>Спасибо!


Использовать многопоточность пробовали? Сделайте обработку wmi запросов в отдельных потоках и по мере их завершения заполняйте форму. Этим освободите поток формы и он будет доступна.
Re[2]: Оптимизация кода программы
От: nettro  
Дата: 02.04.12 13:45
Оценка:
Здравствуйте, Glas, Вы писали:

G>Здравствуйте, nettro, Вы писали:


N>>Доброго времени суток!

N>>Проблема в следующем: написал программу на c#, которая опрашивает сеть на наличие пингующихся компьютеров в сети, и если компьютер пингуется, ему посылаются wmi запросы по сбору информации о его конфигурации (пока собирается инфа о процессоре, памяти, хардах и видеоадаптере) и всё это дело выводиться в richTextBox (планируется записывать всё это дело в базу, но пока по этому поводу не думал). Так вот, если в сети доступны компов 30, то данная операция опроса выполняется минут 5 и при выполнении форма программы просто зависает и с ней ничего нельзя сделать...
N>>Помогите пожалуйста решить эту проблему, что бы уменьшить время выполнения программы и главное что бы программа не подвисала?

N>>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.


N>>Спасибо!


G>Использовать многопоточность пробовали? Сделайте обработку wmi запросов в отдельных потоках и по мере их завершения заполняйте форму. Этим освободите поток формы и он будет доступна.


Ну я пытаюсь привязать BackgroundWorker к проге, как написано в mdsn этот класс как раз выполняет операцию в отдельном потоке. Но пока всё безуспешно...
Re[3]: Оптимизация кода программы
От: Glas  
Дата: 02.04.12 13:58
Оценка:
Здравствуйте, nettro, Вы писали:

N>Ну я пытаюсь привязать BackgroundWorker к проге, как написано в mdsn этот класс как раз выполняет операцию в отдельном потоке. Но пока всё безуспешно...


Ваш код для работы с BackgroundWorker показать можете? Ну или если с ним разобраться не можете, можно использовать класс Thread.
Re: Оптимизация кода программы
От: motormanyak Земля  
Дата: 02.04.12 14:41
Оценка:
Здравствуйте, nettro, Вы писали:

N>Доброго времени суток!

N>Проблема в следующем: написал программу на c#, которая опрашивает сеть на наличие пингующихся компьютеров в сети, и если компьютер пингуется, ему посылаются wmi запросы по сбору информации о его конфигурации (пока собирается инфа о процессоре, памяти, хардах и видеоадаптере) и всё это дело выводиться в richTextBox (планируется записывать всё это дело в базу, но пока по этому поводу не думал). Так вот, если в сети доступны компов 30, то данная операция опроса выполняется минут 5 и при выполнении форма программы просто зависает и с ней ничего нельзя сделать...
N>Помогите пожалуйста решить эту проблему, что бы уменьшить время выполнения программы и главное что бы программа не подвисала?

N>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.


N>Спасибо!


Здесь BackgroundWorker не совсем подходит. В него можно вынести цикл опроса, что разлочит главное окно, но не ускорит процесс выполнения. Чтобы ускорить процесс выполнения, каждую итерацию следует вынести в отдельный поток (класс Thread).

Код в помощь

        public TResult[] Execute<T, TResult>(Func<T, TResult> func, ICollection<T> collection)
        {
            IAsyncResult[] handles = new IAsyncResult[collection.Count()];
            int i = 0;
            foreach (T element in collection)
                handles[i++] = func.BeginInvoke(element, null, null);

            i = 0;
            TResult[] result = new TResult[collection.Count()];
            foreach (IAsyncResult handle in handles)
                result[i++] = func.EndInvoke(handle);
            return result;
            //dispath an event here
        }


Func<T, TResult> func — функция, которая собирает инфу с компа
ICollection<T> collection — коллекция доступных компов

вызов:

String[] comps[] = new String[] {......};
Func<String, String> func = new Func<String, String>( host => Collect_Info_And_Return_String(host) );
String[] results = null;
new Thread( _ => results = Execute<String, String>(func, comps) ).Start();


results лучше прибиндить к richTextBox. так не надо будет следить за окончанием выполнения потока. или можно добавить событие (см. выше) и по событию отображать результат
еще следует помнить, что элементы коллекции collection будут обрабатываться функцией func в произвольном порядке
In God We Trust
Re: Оптимизация кода программы
От: Fortnum  
Дата: 02.04.12 15:37
Оценка:
Здравствуйте, nettro, Вы писали:

N>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.


WPF или WinForms?
Re[2]: Оптимизация кода программы
От: Fortnum  
Дата: 02.04.12 15:43
Оценка:
Здравствуйте, motormanyak, Вы писали:

N>>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.

M>Здесь BackgroundWorker не совсем подходит. В него можно вынести цикл опроса, что разлочит главное окно, но не ускорит процесс выполнения. Чтобы ускорить процесс выполнения, каждую итерацию следует вынести в отдельный поток (класс Thread).

А где же обновление ProgressBar'а?
Re[3]: Оптимизация кода программы
От: motormanyak Земля  
Дата: 02.04.12 16:21
Оценка: 1 (1)
Здравствуйте, Fortnum, Вы писали:

F>Здравствуйте, motormanyak, Вы писали:


N>>>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.

M>>Здесь BackgroundWorker не совсем подходит. В него можно вынести цикл опроса, что разлочит главное окно, но не ускорит процесс выполнения. Чтобы ускорить процесс выполнения, каждую итерацию следует вынести в отдельный поток (класс Thread).

F>А где же обновление ProgressBar'а?


да запросто

        public TResult[] Execute<T, TResult>(Func<T, TResult> func, ICollection<T> collection)
        {
            IAsyncResult[] handles = new IAsyncResult[collection.Count()];
            int i = 0;
            foreach (T element in collection)
                handles[i++] = func.BeginInvoke(element, null, null);

            i = 0;
            int percent = 0;
            TResult[] result = new TResult[collection.Count()];
            foreach (IAsyncResult handle in handles)
            {
                result[i++] = func.EndInvoke(handle);
                percent = Math.Round(i / collection.Count * 100);
                progressBar.Invoke((Action)(delegate {  p.Value = percent; }));
            }
            return result;
            //dispatсh an event here
        }


но по-хорошему, все это надо вынести в отдельный класс, который не будет знать о progressBar. а на месте progressBar.Invoke диспатчить событие (возможно даже тогоже типа, что и BackgroundWorker диспатчит).

п.с. последние изменения не проверял, но думаю должно сработать
In God We Trust
Re[4]: Оптимизация кода программы
От: Fortnum  
Дата: 02.04.12 16:36
Оценка:
Здравствуйте, motormanyak, Вы писали:

F>>А где же обновление ProgressBar'а?

M>да запросто
M>но по-хорошему, все это надо вынести в отдельный класс, который не будет знать о progressBar. а на месте progressBar.Invoke диспатчить событие (возможно даже тогоже типа, что и BackgroundWorker диспатчит).
M>п.с. последние изменения не проверял, но думаю должно сработать

А почему бы тогда не воспользоваться BackgroundWorker'ом, который уже как бы представляет собой этот отдельный класс? По-хорошему тут не в один поток это все надо засовывать, а использовать AsyncCallback. И ни в коем случае не вызывать EndInvoke() раньше времени, тем более в цикле. Иначе первый же отсутствующий в сетке хост из списка застопорит этот отдельный поток в своих таймаутах и никакой радости вы не получите. Отдельный класс, конечно, напрашивается. Обновление ProgressBar'а выполнять в AsyncCallback'ах.

Топикстартеру пример работы ProgressBar vs. BackgroundWorker на WPF.
Re[4]: Оптимизация кода программы
От: nettro  
Дата: 02.04.12 16:55
Оценка:
Здравствуйте, Glas, Вы писали:

G>Здравствуйте, nettro, Вы писали:


N>>Ну я пытаюсь привязать BackgroundWorker к проге, как написано в mdsn этот класс как раз выполняет операцию в отдельном потоке. Но пока всё безуспешно...


G>Ваш код для работы с BackgroundWorker показать можете? Ну или если с ним разобраться не можете, можно использовать класс Thread.


http://ifolder.ru/29673465
вот сюда залил свой проект, делал в vs2010

Здравствуйте, Fortnum, Вы писали:

F>Здравствуйте, nettro, Вы писали:


N>>p.s. Если кто то откликнется на тему и поможет на конкретном примере привязать BackgroundWorker и ProgressBar к проге, а то сколько не пытаюсь по статьям с msdn, как то пока не получается... По необходимости могу прислать проект с кодом.


F>WPF или WinForms?


Если я правильно понял описание что такое WPF на вики, то моя прога это WinForms
Re[5]: Оптимизация кода программы
От: nettro  
Дата: 02.04.12 17:01
Оценка:
Здравствуйте, nettro, Вы писали:

N>Здравствуйте, Glas, Вы писали:


G>>Здравствуйте, nettro, Вы писали:


N>>>Ну я пытаюсь привязать BackgroundWorker к проге, как написано в mdsn этот класс как раз выполняет операцию в отдельном потоке. Но пока всё безуспешно...


G>>Ваш код для работы с BackgroundWorker показать можете? Ну или если с ним разобраться не можете, можно использовать класс Thread.


N>http://ifolder.ru/29673465

N>вот сюда залил свой проект, делал в vs2010

ой, только по этому пути, на ifolder лежит проект без работы с BackgroundWorker... т.к. пытаюсь на работе его прикрутить, ничего не вышло, и в конце дня забыл отбекапить его...
Re[5]: Оптимизация кода программы
От: igor-booch Россия  
Дата: 02.04.12 18:56
Оценка:
F>А почему бы тогда не воспользоваться BackgroundWorker'ом,

BackgroundWorker'ом можно корректно (без Abort) завершить поток при необходимости. Автору это может и не нужно.
http://rsdn.ru/Info/rules.xml
Re[6]: Оптимизация кода программы
От: Fortnum  
Дата: 02.04.12 19:39
Оценка:
Здравствуйте, igor-booch, Вы писали:

F>>А почему бы тогда не воспользоваться BackgroundWorker'ом,

IB>BackgroundWorker'ом можно корректно (без Abort) завершить поток при необходимости. Автору это может и не нужно.

Не понял, каким образом этот факт влияет на выбор между использованием BackgroundWorker'а и запуском отдельного Thread'а? Прерывать Thread Abort'ом вообще крайне не рекомендуется. К тому же, Abort'ом при необходимости можно и BackgroundWorker завершить:

static void Main(string[] args)
{
    var backgroundWorker = new BackgroundWorker()
    {
        WorkerReportsProgress = true
    };

    backgroundWorker.DoWork += (o, e) =>
    {
        backgroundWorker.ReportProgress(0, Thread.CurrentThread);

        while (true)
        {
            Console.Write('.');
        }
    };

    backgroundWorker.ProgressChanged += (o, e) =>
    {
        var thread = (Thread)e.UserState;

        Thread.Sleep(10);

        thread.Abort();
    };

    backgroundWorker.RunWorkerAsync();
            
    Console.ReadKey();
}
Re[6]: Оптимизация кода программы
От: nettro  
Дата: 03.04.12 05:15
Оценка:
Извиняюсь за наглость, но никто не смотрел код с проектом? Если у кого то есть возможность объяснить или показать как на его примере внедрить BackgroundWorker, буду Вам очень благодарен!! а то что то после 2х суток чтения разных источников, в голове появились не знания, а путаница какая то...
Re[7]: Оптимизация кода программы
От: Fortnum  
Дата: 03.04.12 06:25
Оценка: 23 (2) +1
Здравствуйте, nettro, Вы писали:

N>Извиняюсь за наглость, но никто не смотрел код с проектом? Если у кого то есть возможность объяснить или показать как на его примере внедрить BackgroundWorker, буду Вам очень благодарен!! а то что то после 2х суток чтения разных источников, в голове появились не знания, а путаница какая то...


Смотрю. Во-первых, у меня на компьютере адреса не только IPv4, поэтому вот эту строчку получения IP-адреса:

System.Net.IPAddress ipLocalHost = System.Net.Dns.GetHostEntry(nameLocalHost).AddressList[0];


надо переписать, например, вот так:

var ipLocalHost = Dns.GetHostEntry(nameLocalHost).AddressList.Where(ipAddr => ipAddr.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault();

if (ipLocalHost == null)
    MessageBox.Show("Не найдено ни одного IPv4-адреса.");


Во-вторых, форма подвисает не из-за самого процесса пропинговки, т.к. вызываете пропинговку вы асинхронным способом. Пингуете вы по IP-адресу, а не по имени хоста, поэтому задержек от DNS-сервера не должно быть, значит вызов Ping.SendAsync можно оставить как есть, в UI-потоке. Проблема в обработчике события Ping.PingCompleted, который вызывается не в рабочем потоке — потоке из пула потоков, в котором, собственно, производился пинг, а вызывается в том же UI-потоке, из которого был вызван метод Ping.SendAsync. А это значит, что все то, что происходит в обработчике Ping.PingCompleted тормозит UI. А происходит у вас там вызов метода WmiInfo(e.Reply.Address.ToString()). Тупо прерывая кнопкой Pause во время работы вашего приложения под отладкой, когда форма висит, видно, что задержки возникают на вызове ManagementScope.Connect().

Короче, вызов WmiInfo надо выносить в рабочий поток. Для этого не обязательно использовать BackgroundWorker. Можно воспользоваться методом ThreadPool.QueueUserWorkItem:

ThreadPool.QueueUserWorkItem(state => WmiInfo(e.Reply.Address.ToString()));


Но надо иметь в виду, что теперь метод WmiInfo будет исполняться не-UI-потоком. Более того, этот метод будет исполняться многими потоками параллельно, то есть одновременно. В первую, наверное, очередь это приведет к ошибке "Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on", которая возникнет на первом же вашем richTextBox1.Text += "..." в WmiInfo. Идея в том, что из не-UI-потока нельзя обращаться к свойствам и методам UI-контролов. К ним можно обращаться только из того потока, в котором эти контролы были созданы. Чтобы понять, почему существует такое ограничение, достаточно представить себе, что если бы такое обращение к UI-контролам из разных потоков было бы возможно, то в вашем richTextBox1 вы получили бы просто мусор, т.к. каждый параллельно выполняющийся WmiInfo валил бы туда свои строчки, независимо от других. А т.к. в UI каждое действие над UI-контролом может вызывать различную реакцию, и последовательность этой реакции критически важна, то и существует такое ограничение на обращение к UI-контролам только из UI-потока.

Нет, вы конечно же можете каждый ваш richTextBox1.Text += "..." в WmiInfo обернуть в посылку задачи по выводу этой строки UI-потоку. Например, так:

BeginInvoke(((Action)(() => richTextBox1.Text += "...")));


Но это не спасет вас от рассинхронизации вывода в этот richTextBox1 между различными экземплярами параллельно исполняющихся WmiInfo. Поэтому, в итоге, хоть и без Exception'ов, но в richTextBox1 вы получите все тот же мусор. Как вариант, использовать для форматирования текста в WmiInfo экземпляр StringBuilder, а вывод в richTextBox1 делать в конце WmiInfo. Надо только учесть еще рассинхронизацию вызова richTextBox1.Text += "...", который будет идти непосредственно перед вызовом ThreadPool.QueueUserWorkItem(state => WmiInfo(...)).

BackgroundWorker'ом пока не заморачивайтесь. Вам важнее понять, что происходит и почему. Тот же ProgressBar легко делается и без BackgroundWorker'а. Этот BackgroundWorker — это лишь один из способов, и в большинстве случаев не самый лучший.
Re[5]: Оптимизация кода программы
От: motormanyak Земля  
Дата: 03.04.12 07:24
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>А почему бы тогда не воспользоваться BackgroundWorker'ом, который уже как бы представляет собой этот отдельный класс?

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

F>По-хорошему тут не в один поток это все надо засовывать, а использовать AsyncCallback.

Тут и так не один поток используется. Вызывать эту функцию надо в еще одном отдельном потоке (см. пост выше)

F>И ни в коем случае не вызывать EndInvoke() раньше времени, тем более в цикле. Иначе первый же отсутствующий в сетке хост из списка застопорит этот отдельный поток в своих таймаутах и никакой радости вы не получите.

EndInvoke в цикле ничего плохого не сделает: если поток завершился, то EndInvoke вернет управление мгновенно. А чтоб отдельный поток не завис навсегда, нужно это в функции предусмотреть.

F>Обновление ProgressBar'а выполнять в AsyncCallback'ах.

Согласен, поспешил когда писал
In God We Trust
Re[6]: Оптимизация кода программы
От: Fortnum  
Дата: 03.04.12 07:42
Оценка:
Здравствуйте, motormanyak, Вы писали:

F>>А почему бы тогда не воспользоваться BackgroundWorker'ом, который уже как бы представляет собой этот отдельный класс?

M>BackgroundWorker здесь не подходит, как я раньше писал, из-за того, что сбор информации лучше проводить в разных потоках одновременно, а не в одном по очереди.

Точно, ждать ответа на пинг в отдельном потоке бессмысленно — не подходит.

F>>По-хорошему тут не в один поток это все надо засовывать, а использовать AsyncCallback.

M>Тут и так не один поток используется. Вызывать эту функцию надо в еще одном отдельном потоке (см. пост выше)

А для этого как раз сгодится.

F>>И ни в коем случае не вызывать EndInvoke() раньше времени, тем более в цикле. Иначе первый же отсутствующий в сетке хост из списка застопорит этот отдельный поток в своих таймаутах и никакой радости вы не получите.

M>EndInvoke в цикле ничего плохого не сделает: если поток завершился, то EndInvoke вернет управление мгновенно. А чтоб отдельный поток не завис навсегда, нужно это в функции предусмотреть.

А как предусмотреть? Не вызывать EndInvoke, а ждать Callback
Re[8]: Оптимизация кода программы
От: nettro  
Дата: 03.04.12 07:51
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Здравствуйте, nettro, Вы писали:


N>>Извиняюсь за наглость, но никто не смотрел код с проектом? Если у кого то есть возможность объяснить или показать как на его примере внедрить BackgroundWorker, буду Вам очень благодарен!! а то что то после 2х суток чтения разных источников, в голове появились не знания, а путаница какая то...


F>Смотрю. Во-первых, у меня на компьютере адреса не только IPv4, поэтому вот эту строчку получения IP-адреса:


F>
System.Net.IPAddress ipLocalHost = System.Net.Dns.GetHostEntry(nameLocalHost).AddressList[0];


F>надо переписать, например, вот так:


F>
var ipLocalHost = Dns.GetHostEntry(nameLocalHost).AddressList.Where(ipAddr => ipAddr.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault();

if (ipLocalHost == null)
    MessageBox.Show("Не найдено ни одного IPv4-адреса.");


F>Во-вторых, форма подвисает не из-за самого процесса пропинговки, т.к. вызываете пропинговку вы асинхронным способом. Пингуете вы по IP-адресу, а не по имени хоста, поэтому задержек от DNS-сервера не должно быть, значит вызов Ping.SendAsync можно оставить как есть, в UI-потоке. Проблема в обработчике события Ping.PingCompleted, который вызывается не в рабочем потоке — потоке из пула потоков, в котором, собственно, производился пинг, а вызывается в том же UI-потоке, из которого был вызван метод Ping.SendAsync. А это значит, что все то, что происходит в обработчике Ping.PingCompleted тормозит UI. А происходит у вас там вызов метода WmiInfo(e.Reply.Address.ToString()). Тупо прерывая кнопкой Pause во время работы вашего приложения под отладкой, когда форма висит, видно, что задержки возникают на вызове ManagementScope.Connect().


F>Короче, вызов WmiInfo надо выносить в рабочий поток. Для этого не обязательно использовать BackgroundWorker. Можно воспользоваться методом ThreadPool.QueueUserWorkItem:


F>
ThreadPool.QueueUserWorkItem(state => WmiInfo(e.Reply.Address.ToString()));


F>Но надо иметь в виду, что теперь метод WmiInfo будет исполняться не-UI-потоком. Более того, этот метод будет исполняться многими потоками параллельно, то есть одновременно. В первую, наверное, очередь это приведет к ошибке "Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on", которая возникнет на первом же вашем richTextBox1.Text += "..." в WmiInfo. Идея в том, что из не-UI-потока нельзя обращаться к свойствам и методам UI-контролов. К ним можно обращаться только из того потока, в котором эти контролы были созданы. Чтобы понять, почему существует такое ограничение, достаточно представить себе, что если бы такое обращение к UI-контролам из разных потоков было бы возможно, то в вашем richTextBox1 вы получили бы просто мусор, т.к. каждый параллельно выполняющийся WmiInfo валил бы туда свои строчки, независимо от других. А т.к. в UI каждое действие над UI-контролом может вызывать различную реакцию, и последовательность этой реакции критически важна, то и существует такое ограничение на обращение к UI-контролам только из UI-потока.


F>Нет, вы конечно же можете каждый ваш richTextBox1.Text += "..." в WmiInfo обернуть в посылку задачи по выводу этой строки UI-потоку. Например, так:


F>
BeginInvoke(((Action)(() => richTextBox1.Text += "...")));


F>Но это не спасет вас от рассинхронизации вывода в этот richTextBox1 между различными экземплярами параллельно исполняющихся WmiInfo. Поэтому, в итоге, хоть и без Exception'ов, но в richTextBox1 вы получите все тот же мусор. Как вариант, использовать для форматирования текста в WmiInfo экземпляр StringBuilder, а вывод в richTextBox1 делать в конце WmiInfo. Надо только учесть еще рассинхронизацию вызова richTextBox1.Text += "...", который будет идти непосредственно перед вызовом ThreadPool.QueueUserWorkItem(state => WmiInfo(...)).


F>BackgroundWorker'ом пока не заморачивайтесь. Вам важнее понять, что происходит и почему. Тот же ProgressBar легко делается и без BackgroundWorker'а. Этот BackgroundWorker — это лишь один из способов, и в большинстве случаев не самый лучший.


Во-первых огромное Вам спасибо за ответ!!! Вы единственный человек с кучи форумов, который хоть посмотрел мой горе проект и откомментировал его по факту, а не фразами "почитайте msdn", который я читал, но в силу своей неопытности программирования, мало что полезного вынес оттуда...

По поводу отсутствия в программе IPv6, я пока ограничился IPv4 ибо он используется в 98% случаев, да и я не рассчитываю что моя программа будет претендовать на какие то коммерческие решения или что то подобное, пишу её для института и в помощь системным администраторам, т.к. сам сталкивался в сборе подобной информации, а т.к. пиратсвом заниматься не хочется, смотрел в сторону бесплатного софта, выбор которого сводился к 1-2 программам подобного типа со своими минусами, а в больших конторах, другие деньги, и там нет смысла искать бесплатные программы для инвентаризации железа и софта. Но за комментарий и пример кода спасибо, в дальнейшем, если получиться заставить работать программу с потоками, постараюсь обязательно учесть Ваше замечание.

По поводу функции WmiInfo, как Вы могли заметить, в коде описания кнопочки запуска, есть закомментированная строчка вызова WmiINfo:
foreach (string ipRemoteHost in ipRemoteHostList)
{
    asinhroPing(ipRemoteHost);
    //WmiInfo();
}

с самого начала WmiInfo запускалось там, перенос её вызова в funkPingCompleted было тестом, для оценки изменится ли время выполнения или нет.

По поводу
F>Короче, вызов WmiInfo надо выносить в рабочий поток. Для этого не обязательно использовать BackgroundWorker. Можно воспользоваться методом ThreadPool.QueueUserWorkItem:
ThreadPool.QueueUserWorkItem(state => WmiInfo(e.Reply.Address.ToString()));


не могли бы Вы подсказать, как правильнее поступить с функцией WmiInfo, вынести приведённый Вами кусочек кода это в отдельную функцию или вставить этот код в обработку кнопки запуска программы, или же оставить её в этом где она находится на данных момент?

F>Как вариант, использовать для форматирования текста в WmiInfo экземпляр StringBuilder, а вывод в richTextBox1 делать в конце WmiInfo. Надо только учесть еще рассинхронизацию вызова richTextBox1.Text += "...", который будет идти непосредственно перед вызовом ThreadPool.QueueUserWorkItem(state => WmiInfo(...)).


Что касается richTextBox1, я пока не знаю временно это или оставить его, но в дальнейшем я планирую как то всё эти данные полученные с компьютеров записывать в базу и в следствии этого хотелось бы узнать узнать мнение с высоты Вашего опыта, как это лучше организовать?
Большое спасибо!
Re[9]: Оптимизация кода программы
От: Fortnum  
Дата: 03.04.12 08:18
Оценка: 1 (1)
Здравствуйте, nettro, Вы писали:

N>По поводу отсутствия в программе IPv6, я пока ограничился IPv4 ибо он используется в 98% случаев


Вы на будущее учтите также еще то, что не все сети имеют класс /24, т.е. маску 255.255.255.0. Вполне нормально себе, к примеру, существуют сети /27, т.е. 255.255.255.224. В них сама подсеть может иметь, к примеру, адрес 192.168.1.32, диапазон адресов хостов этой подсети будет 192.168.1.33-192.168.1.62, а широковещательный адрес будет 192.168.1.63. Возможны и другие маски. То есть алгоритм обхода узлов локальной подсети. следовательно, надо улучшить.

N>По поводу функции WmiInfo, как Вы могли заметить, в коде описания кнопочки запуска, есть закомментированная строчка вызова WmiINfo:

N>с самого начала WmiInfo запускалось там, перенос её вызова в funkPingCompleted было тестом, для оценки изменится ли время выполнения или нет.

Так обращение к WMI удаленного компьютера должно происходить только при успешном пинге. А если раскоментировать эту строчку, то получится, что вы будете обходить все компьютеры в любом случае, независимо от результатов пинга. Кроме того, вызов WmiInfo в этом случае остается абсолютно четко в UI-потоке.

F>>Короче, вызов WmiInfo надо выносить в рабочий поток. Для этого не обязательно использовать BackgroundWorker. Можно воспользоваться методом ThreadPool.QueueUserWorkItem:

N>не могли бы Вы подсказать, как правильнее поступить с функцией WmiInfo, вынести приведённый Вами кусочек кода это в отдельную функцию или вставить этот код в обработку кнопки запуска программы, или же оставить её в этом где она находится на данных момент?

Ну вот на том месте, где WmiInfo вызывается сейчас, в funkPingCompleted, и вставить эту строчку (заменить прямой вызов WmiInfo на постановку вызова WmiInfo в очередь пулу потоков). Закомментировать в WmiInfo обращения к richTextBox1 и другим контролам, если они там есть, а в конце WmiInfo поставить:

BeginInvoke(((Action)(() => richTextBox1.Text += string.Format("WmiInfo of {0} done.", a))));


, в обработчик catch то же самое, только вывести, к примеру, Exception.Message. Увидеть как все работает.

N>Что касается richTextBox1, я пока не знаю временно это или оставить его, но в дальнейшем я планирую как то всё эти данные полученные с компьютеров записывать в базу и в следствии этого хотелось бы узнать узнать мнение с высоты Вашего опыта, как это лучше организовать?


Оставьте пока. Надо только строку для вывода копить в WmiInfo в локальной переменной, а вывод в richTextBox1 сделать один раз в самом конце этого метода. А вообще, я бы порекомендовал отделить функционал по сбору информации с компьютеров от UI, выделив этот функционал в отдельный класс. Если интересно, чуть позже напишу как именно.
Re[10]: Оптимизация кода программы
От: nettro  
Дата: 03.04.12 08:36
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Вы на будущее учтите также еще то, что не все сети имеют класс /24, т.е. маску 255.255.255.0. Вполне нормально себе, к примеру, существуют сети /27, т.е. 255.255.255.224. В них сама подсеть может иметь, к примеру, адрес 192.168.1.32, диапазон адресов хостов этой подсети будет 192.168.1.33-192.168.1.62, а широковещательный адрес будет 192.168.1.63. Возможны и другие маски. То есть алгоритм обхода узлов локальной подсети. следовательно, надо улучшить.


я планировал добавить ещё 2 обычных textBox-а, в которые вводился бы интересующий диапазон адресов и по ним происходил бы обход. Не сделал этого из-за очевидных причин, пока пытаюсь заставить работать то что есть)
Не знаю, решит ли это проблему с масками как вы правильно заметили, но пока мыслей по улучшению алгоритма обхода нет

F>Так обращение к WMI удаленного компьютера должно происходить только при успешном пинге. А если раскоментировать эту строчку, то получится, что вы будете обходить все компьютеры в любом случае, независимо от результатов пинга. Кроме того, вызов WmiInfo в этом случае остается абсолютно четко в UI-потоке.


F>>>Короче, вызов WmiInfo надо выносить в рабочий поток. Для этого не обязательно использовать BackgroundWorker. Можно воспользоваться методом ThreadPool.QueueUserWorkItem:

N>>не могли бы Вы подсказать, как правильнее поступить с функцией WmiInfo, вынести приведённый Вами кусочек кода это в отдельную функцию или вставить этот код в обработку кнопки запуска программы, или же оставить её в этом где она находится на данных момент?

F>Ну вот на том месте, где WmiInfo вызывается сейчас, в funkPingCompleted, и вставить эту строчку (заменить прямой вызов WmiInfo на постановку вызова WmiInfo в очередь пулу потоков). Закомментировать в WmiInfo обращения к richTextBox1 и другим контролам, если они там есть, а в конце WmiInfo поставить:


F>
F>BeginInvoke(((Action)(() => richTextBox1.Text += string.Format("WmiInfo of {0} done.", a))));
F>


F>, в обработчик catch то же самое, только вывести, к примеру, Exception.Message. Увидеть как все работает.

Спасибо сейчас попробую так сделать.

F>Оставьте пока. Надо только строку для вывода копить в WmiInfo в локальной переменной, а вывод в richTextBox1 сделать один раз в самом конце этого метода. А вообще, я бы порекомендовал отделить функционал по сбору информации с компьютеров от UI, выделив этот функционал в отдельный класс. Если интересно, чуть позже напишу как именно.

Если Вас не затруднит буду очень Вам благодарен!!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.