Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
1
.NET 4.x

Как оптимизировать код, где используется много методов .Contains?

22.04.2013, 08:06. Показов 2649. Ответов 30
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте! Есть задача поиска всех url'ов на каком то сайте и найти в них битые/небитые. Задачу решил с использованием Selenium WebDriver. В его помощью я легко получаю все нужные мне ссылки. Но вот только после того, как страница сайта была загружена и из её кода были выдраны url'ы, мне нужно проверить, не обрабатывал ли я уже такую url'ку, нет ли её уже в каком нибудь списке. Для этого использую метод .Contains. Вот только использую аж 5 штук подряд) И получается ситуация, что страница уже загружена, а из-за моих проверок прога висит. Можно ли как то оптимизировать мой код:

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
static void Main(string[] args)
        {
            IWebDriver driver = new ChromeDriver();
            //----------------------------------------------
            
            ArrayList brokenLinks = new ArrayList();
            ArrayList workingLinks = new ArrayList();
            ArrayList visitedLinks = new ArrayList();
            ArrayList externalLinksToVisit = new ArrayList();
            Stack<string> internalLinksToVisit = new Stack<string>();
            bool needToStop = false;
            string domainName = "http://isokor.pinstudio.ru/";
            string url = string.Empty;
            string startUrl = string.Empty; 
            HttpWebRequest webRequest = null;
            HttpWebResponse response = null;
 
            internalLinksToVisit.Push(domainName);
 
            while (needToStop == false)
            {
                startUrl = internalLinksToVisit.Pop();
                driver.Navigate().GoToUrl(startUrl);
                visitedLinks.Add(startUrl);
 
                try
                {
                    webRequest = (HttpWebRequest)WebRequest.Create(startUrl);
                    webRequest.AllowAutoRedirect = false;
                    webRequest.Timeout = 5000;
 
                    response = (HttpWebResponse)webRequest.GetResponse();
                    Console.WriteLine(startUrl + " - " + ((int)response.StatusCode).ToString());
 
                    if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Moved && response.StatusCode != HttpStatusCode.MovedPermanently)
                    {
                        brokenLinks.Add(startUrl);
                    }
                    else
                    {
                        workingLinks.Add(startUrl);
                    }
                }
                catch (NotSupportedException)
                {
                    Console.WriteLine(startUrl + " - " + "невозможно определить код ответа");
                }
                catch (WebException e)
                {
                    brokenLinks.Add(startUrl + " - " + ((int)((HttpWebResponse)e.Response).StatusCode).ToString());
                    Console.WriteLine(startUrl + " - " + ((int)((HttpWebResponse)e.Response).StatusCode).ToString());
                }
                finally
                {
                    response.Close();
                }
 
                foreach (IWebElement element in driver.FindElements(By.TagName("a")))
                {
                    url = element.GetAttribute("href");
 
                    if (url != null)
                    {
                        if (url.Contains("#"))
                        {
                            continue;
                        }
 
                        if (internalLinksToVisit.Contains(url) == false && externalLinksToVisit.Contains(url) == false && visitedLinks.Contains(url) == false)
                        {
                            if (url.Contains(domainName) == true)
                            {
                                internalLinksToVisit.Push(url);
                            }
                            else
                            {
                                externalLinksToVisit.Add(url);
                            }
                        }
                    }
                }
 
                if (internalLinksToVisit.Count == 0)
                {
                    needToStop = true;
                }
            }
            
            //----------------------------------------------
 
            driver.Quit();
            Console.ReadKey();
        }
    }
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.04.2013, 08:06
Ответы с готовыми решениями:

Код потребляет очень много памяти. Подскажите как оптимизировать?
Есть код на C++ (компилируется под GCC) - подсчёт коэффициентов осцилляторной системы методом...

Оптимизировать код парсинга страниц. Используется SimpleHtmlDom
Как оптимизировать подобное: $url2=('http://cайт1/'); $table2 = array(); $data2 =...

Где научиться оптимизировать код?
Подскажите хорошие уроки, желательно на русском, по отладке ошибок ПХП, нахождение, исправление...

Как оптимизировать на чтение, если много оперативки?
Есть базы суммарным размером гиг 30. Есть сервер виртуальный с 60 гигами памяти. Как мне сделать...

30
Эксперт Python
4632 / 2050 / 361
Регистрация: 17.03.2012
Сообщений: 10,133
Записей в блоге: 6
22.04.2013, 08:49 2
Используйте Dictionary с вашими url'ами в качестве ключей.
Там, правда, добавление медленнее.
0
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 11:52  [ТС] 3
Цитата Сообщение от dondublon Посмотреть сообщение
Используйте Dictionary с вашими url'ами в качестве ключей.
Там, правда, добавление медленнее.
А чем мне это поможет? Насколько я знаю Dictionary - это штука, чтобы заменить значения переменных какими то человекопонятными словами. Не?
0
Эксперт Python
4632 / 2050 / 361
Регистрация: 17.03.2012
Сообщений: 10,133
Записей в блоге: 6
22.04.2013, 12:07 4
Цитата Сообщение от Vlad10 Посмотреть сообщение
А чем мне это поможет? Насколько я знаю Dictionary - это штука, чтобы заменить значения переменных какими то человекопонятными словами. Не?
Dictionary - набор пар "ключ-значение", оптимизированный для поиска по ключу.
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
22.04.2013, 14:13 5
Vlad10, замените просто Arraylist на HashSet<string> Все остальное оставьте как есть.

Добавлено через 1 минуту
И на будущее: откажитесь от ВСЕХ случаев использования ArrayList, как глючного тормознутого... Фигни...

Добавлено через 1 минуту
dondublon, словарь тут не при чем, достаточно сета
0
Эксперт Python
4632 / 2050 / 361
Регистрация: 17.03.2012
Сообщений: 10,133
Записей в блоге: 6
22.04.2013, 14:20 6
Цитата Сообщение от Psilon Посмотреть сообщение
dondublon, словарь тут не при чем, достаточно сета
Внутри словаря все равно сет, просто про отдельный класс был не в курсе.
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
22.04.2013, 14:31 7
dondublon, то да
0
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 15:03  [ТС] 8
Цитата Сообщение от Psilon Посмотреть сообщение
Vlad10, замените просто Arraylist на HashSet<string> Все остальное оставьте как есть.
И это действительно так, время простоя на самой заполненной ссылками странице не больше секунды. Спасибо! Меня в принципе устраивает. Другое дело, в цикле есть кусок кода:
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
                try
                {
                    webRequest = (HttpWebRequest)WebRequest.Create(startUrl);
                    webRequest.AllowAutoRedirect = false;
                    webRequest.Timeout = 5000;
 
                    response = (HttpWebResponse)webRequest.GetResponse();
                    Console.WriteLine(startUrl + " - " + ((int)response.StatusCode).ToString());
 
                    if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Moved && response.StatusCode != HttpStatusCode.MovedPermanently)
                    {
                        brokenLinks.Add(startUrl);
                    }
                    else
                    {
                        workingLinks.Add(startUrl);
                    }
                }
                catch (NotSupportedException)
                {
                    Console.WriteLine(startUrl + " - " + "невозможно определить код ответа");
                }
                catch (WebException e)
                {
                    brokenLinks.Add(startUrl + " - " + ((int)((HttpWebResponse)e.Response).StatusCode).ToString());
                    Console.WriteLine(startUrl + " - " + ((int)((HttpWebResponse)e.Response).StatusCode).ToString());
                }
                finally
                {
                    response.Close();
                }
Это чтобы узнать код ответа страницы. Он мне нужен, но он подтормаживает мой цикл где то на 0,2-0,5 секунды. Мне в принципе пофиг уже, даже с этим на каждую страницу уходит где то по секунде + прога будет запускаться по ночам на каком нибудь сервере, но всё же. Хотя тут наверное уже ничего не сделаешь.
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
22.04.2013, 15:06 9
Vlad10, у вас есть возможность сначала создать массив ссылок, а потом в foreAch его обходить?
0
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 15:12  [ТС] 10
Цитата Сообщение от Psilon Посмотреть сообщение
Vlad10, у вас есть возможность сначала создать массив ссылок, а потом в foreAch его обходить?
Да, так сначала и было. Я сначала делал ссылки, потом проверял код. Потом подумал, что быстрее будет сразу ссылку проверять. Думаете, если я верну обратно, то будет быстрее?
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
22.04.2013, 16:10 11
Vlad10, если будет форич, можно будет запустить все обработки параллельно, тогда время работы вряд ли будет дольше времени загрузки самой долгой страницы. Переделайте в foreach, я вам покажу
0
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 17:42  [ТС] 12
Вот переделанный код
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
IWebDriver driver = new ChromeDriver();
            
            //----------------------------------------------
            //Сбор ссылок с сайта
 
            HashSet<string> brokenLinks = new HashSet<string>();
            HashSet<string> workingLinks = new HashSet<string>();
            HashSet<string> visitedLinks = new HashSet<string>();
            HashSet<string> externalLinksToVisit = new HashSet<string>();
            Stack<string> internalLinksToVisit = new Stack<string>();
            bool needToStop = false;
            string domainName = "http://isokor.pinstudio.ru/";
            string url = string.Empty;
            string startUrl = string.Empty; 
            HttpWebRequest webRequest = null;
            HttpWebResponse response = null;
 
            internalLinksToVisit.Push(domainName);
 
            while (needToStop == false)
            {
                startUrl = internalLinksToVisit.Pop();
                driver.Navigate().GoToUrl(startUrl);
                visitedLinks.Add(startUrl);
 
                foreach (IWebElement element in driver.FindElements(By.TagName("a")))
                {
                    url = element.GetAttribute("href");
 
                    if (url != null)
                    {
                        if (url.Contains("#"))
                        {
                            continue;
                        }
 
                        if (internalLinksToVisit.Contains(url) == false && externalLinksToVisit.Contains(url) == false && visitedLinks.Contains(url) == false)
                        {
                            if (url.Contains(domainName) == true)
                            {
                                internalLinksToVisit.Push(url);
                            }
                            else
                            {
                                externalLinksToVisit.Add(url);
                            }
                        }
                    }
                }
 
                if (internalLinksToVisit.Count == 0)
                {
                    needToStop = true;
                }
            }
 
            //----------------------------------------------
            //Получение кодов ответа
 
            foreach (string link in visitedLinks)
            {
                try
                {
                    webRequest = (HttpWebRequest)WebRequest.Create(link);
                    webRequest.AllowAutoRedirect = false;
                    webRequest.Timeout = 5000;
 
                    response = (HttpWebResponse)webRequest.GetResponse();
                    Console.WriteLine(link + " - " + ((int)response.StatusCode).ToString());
 
                    if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Moved && response.StatusCode != HttpStatusCode.MovedPermanently)
                    {
                        brokenLinks.Add(link);
                    }
                    else
                    {
                        workingLinks.Add(link);
                    }
                }
                catch (NotSupportedException)
                {
                    Console.WriteLine(link + " - " + "невозможно определить код ответа");
                }
                catch (WebException e)
                {
                    brokenLinks.Add(link + " - " + ((int)((HttpWebResponse)e.Response).StatusCode).ToString());
                    Console.WriteLine(link + " - " + ((int)((HttpWebResponse)e.Response).StatusCode).ToString());
                }
                finally
                {
                    response.Close();
                }
            }
            
            //----------------------------------------------
Теперь получение кода ответа в фориче.

P/S. У HashSet<string> нету метода .Sort(). Обидно =((((((((
0
28 / 28 / 6
Регистрация: 25.12.2008
Сообщений: 186
22.04.2013, 17:51 13
Цитата Сообщение от Vlad10 Посмотреть сообщение
P/S. У HashSet<string> нету метода .Sort(). Обидно =((((((((
Можно написать...
0
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 17:54  [ТС] 14
Цитата Сообщение от Sinys Посмотреть сообщение
Можно написать...
Можно, но он будет корявый же. А стандартные методы уже максимально крутые.
0
28 / 28 / 6
Регистрация: 25.12.2008
Сообщений: 186
22.04.2013, 18:06 15
Цитата Сообщение от Vlad10 Посмотреть сообщение
ожно, но он будет корявый же. А стандартные методы уже максимально крутые.
по прежнему сортирует элементы... и не настолько оно было бы оптимизировано...
1
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 18:08  [ТС] 16
Цитата Сообщение от Sinys Посмотреть сообщение
по прежнему сортирует элементы... и не настолько оно было бы оптимизировано...
Решил проблему так:
C#
1
2
List<string> ff = visitedLinks.ToList();
            ff.Sort();
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
22.04.2013, 19:28 17
Vlad10, Есть понятие SortedSet == HashSet + sort. Только не вижу смысла в сортировке в данной задаче. А приведение к листу теряет всю эффективность сетов.

я отрефакторил, как мог, ну и добавил параллельность:
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
private static void Foo()
        {
            var driver = new ChromeDriver();
 
            //----------------------------------------------
            //Сбор ссылок с сайта
 
            var brokenLinks = new HashSet<string>();
            var workingLinks = new HashSet<string>();
            var visitedLinks = new HashSet<string>();
            var externalLinksToVisit = new HashSet<string>();
            var internalLinksToVisit = new Stack<string>();
            const string domainName = "http://isokor.pinstudio.ru/";
 
            internalLinksToVisit.Push(domainName);
 
            do
            {
                string startUrl = internalLinksToVisit.Pop();
                driver.Navigate().GoToUrl(startUrl);
                visitedLinks.Add(startUrl);
 
                foreach (IWebElement element in driver.FindElements(By.TagName("a")))
                {
                    string url = element.GetAttribute("href");
 
                    if (url != null)
                    {
                        if (url.Contains("#"))
                        {
                            continue;
                        }
 
                        if (
                            !(internalLinksToVisit.Contains(url) || externalLinksToVisit.Contains(url) ||
                              visitedLinks.Contains(url)))
                        {
                            if (url.Contains(domainName))
                            {
                                internalLinksToVisit.Push(url);
                            }
                            else
                            {
                                externalLinksToVisit.Add(url);
                            }
                        }
                    }
                }
            } while (internalLinksToVisit.Count != 0);
 
            //----------------------------------------------
            //Получение кодов ответа
 
 
            Parallel.ForEach(visitedLinks, link =>
                {
                    HttpWebResponse response = null;
                    try
                    {
                        var webRequest = (HttpWebRequest) WebRequest.Create(link);
                        webRequest.AllowAutoRedirect = false;
                        webRequest.Timeout = 5000;
 
                        response = (HttpWebResponse) webRequest.GetResponse();
                        Console.WriteLine(link + " - " + ((int) response.StatusCode).ToString());
 
                        if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Moved &&
                            response.StatusCode != HttpStatusCode.MovedPermanently)
                        {
                            brokenLinks.Add(link);
                        }
                        else
                        {
                            workingLinks.Add(link);
                        }
                    }
                    catch (NotSupportedException)
                    {
                        Console.WriteLine(link + " - " + "невозможно определить код ответа");
                    }
                    catch (WebException e)
                    {
                        brokenLinks.Add(link + " - " + ((int) ((HttpWebResponse) e.Response).StatusCode).ToString());
                        Console.WriteLine(link + " - " +
                                          ((int) ((HttpWebResponse) e.Response).StatusCode).ToString());
                    }
                    finally
                    {
                        if (response != null) response.Close();
                    }
                });
        }
0
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 19:54  [ТС] 18
Большое спасибо! Сейчас буду пробовать. Сортировка в данной задаче нужна, т.к. сбор ссылок - только самое начало огроменной проги. Разработчикам будет удобнее отсортированное читать.

Пока есть вопросы:
1. Почему во всех переменных написан var? Я знаю, что var сам определяет тип, так типа надёжнее?
2.
C#
1
2
3
if (
                            !(internalLinksToVisit.Contains(url) || externalLinksToVisit.Contains(url) ||
                              visitedLinks.Contains(url)))
Это работает как то быстрее или просто вам не понравилось 3 моих ==false?
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
22.04.2013, 19:59 19
Vlad10,
1. Почему во всех переменных написан var? Я знаю, что var сам определяет тип, так типа надёжнее?
с var проще читать, справа и так написано, что это за переменная. int, char, string, double - можно писать и так, а вот для всяких классов, из записи
C#
1
var person = new Person();
и так понятно, что за person. А запись
C#
1
Person person = new Person();
только загромождает код
2. Это работает как то быстрее или просто вам не понравилось 3 моих ==false?
== false - не принято писать, да и быстрее конечно взять уже готовое значение, чем проводить лишнее сравнение, даже с константой.
0
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 20:06  [ТС] 20
Сделал, теперь коды ответа вообще супер быстро получаю. А во сколько потоков это делается?
И ещё, я сейчас поставил получение кодов в бесконечный цикл, чтобы посмотреть не банит ли меня сервер. Так вот, после 2000 раз у меня уже 2 раз вылезает AggregateException. Если просто нажать на продолжить, то всё продолжается. Что делать? Как это обработать?
0
22.04.2013, 20:06
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
22.04.2013, 20:06
Помогаю со студенческими работами здесь

Много методов или много классов. Что лучше?
Имеется библиотека(ActiveX DLL), в которую, в своё время, было решено складировать функции,...

Конкатенация потребляет много памяти, как можно оптимизировать?
Конкатенация потребляет много памяти. Если учесть, что символ занимает 2 байта, то результирующая...

Где и как используется оператор elseif?
//Лирическое вступление Изучая многие языки программирования, прихожу к выводу - что...

Используется много памяти
Здравствуйте! Недавно откатил Windows 8.1 на Windows 7. После установки новой винды, решил...

Фильмы о танцах (где много, ну очень много танцев)
Привет всем! Может кто-нибудь посоветует мне фильмы, где люди много и классно танцуют???

Для чего используется using внутри методов?
Вот два метода взятых из книги, в одном случае автор поместил весь код в using, в другом нет....


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru