Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 5.00/11: Рейтинг темы: голосов - 11, средняя оценка - 5.00
Vlad10
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
1
.NET 4.x

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

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

Здравствуйте! Есть задача поиска всех 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
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.04.2013, 08:06
Ответы с готовыми решениями:

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

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

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

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

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

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

Добавлено через 1 минуту
dondublon, словарь тут не при чем, достаточно сета
0
dondublon
4076 / 1545 / 292
Регистрация: 17.03.2012
Сообщений: 8,451
Записей в блоге: 5
22.04.2013, 14:20 6
Цитата Сообщение от Psilon Посмотреть сообщение
dondublon, словарь тут не при чем, достаточно сета
Внутри словаря все равно сет, просто про отдельный класс был не в курсе.
0
Psilon
Master of Orion
Эксперт .NET
6058 / 4916 / 903
Регистрация: 10.07.2011
Сообщений: 14,520
Записей в блоге: 5
Завершенные тесты: 4
22.04.2013, 14:31 7
dondublon, то да
0
Vlad10
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
Psilon
Master of Orion
Эксперт .NET
6058 / 4916 / 903
Регистрация: 10.07.2011
Сообщений: 14,520
Записей в блоге: 5
Завершенные тесты: 4
22.04.2013, 15:06 9
Vlad10, у вас есть возможность сначала создать массив ссылок, а потом в foreAch его обходить?
0
Vlad10
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 15:12  [ТС] 10
Цитата Сообщение от Psilon Посмотреть сообщение
Vlad10, у вас есть возможность сначала создать массив ссылок, а потом в foreAch его обходить?
Да, так сначала и было. Я сначала делал ссылки, потом проверял код. Потом подумал, что быстрее будет сразу ссылку проверять. Думаете, если я верну обратно, то будет быстрее?
0
Psilon
Master of Orion
Эксперт .NET
6058 / 4916 / 903
Регистрация: 10.07.2011
Сообщений: 14,520
Записей в блоге: 5
Завершенные тесты: 4
22.04.2013, 16:10 11
Vlad10, если будет форич, можно будет запустить все обработки параллельно, тогда время работы вряд ли будет дольше времени загрузки самой долгой страницы. Переделайте в foreach, я вам покажу
0
Vlad10
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
Sinys
28 / 28 / 6
Регистрация: 25.12.2008
Сообщений: 186
Завершенные тесты: 1
22.04.2013, 17:51 13
Цитата Сообщение от Vlad10 Посмотреть сообщение
P/S. У HashSet<string> нету метода .Sort(). Обидно =((((((((
Можно написать...
0
Vlad10
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 17:54  [ТС] 14
Цитата Сообщение от Sinys Посмотреть сообщение
Можно написать...
Можно, но он будет корявый же. А стандартные методы уже максимально крутые.
0
Sinys
28 / 28 / 6
Регистрация: 25.12.2008
Сообщений: 186
Завершенные тесты: 1
22.04.2013, 18:06 15
Цитата Сообщение от Vlad10 Посмотреть сообщение
ожно, но он будет корявый же. А стандартные методы уже максимально крутые.
по прежнему сортирует элементы... и не настолько оно было бы оптимизировано...
1
Vlad10
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
Psilon
Master of Orion
Эксперт .NET
6058 / 4916 / 903
Регистрация: 10.07.2011
Сообщений: 14,520
Записей в блоге: 5
Завершенные тесты: 4
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
Vlad10
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
Psilon
Master of Orion
Эксперт .NET
6058 / 4916 / 903
Регистрация: 10.07.2011
Сообщений: 14,520
Записей в блоге: 5
Завершенные тесты: 4
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
Vlad10
4 / 4 / 1
Регистрация: 12.06.2011
Сообщений: 111
22.04.2013, 20:06  [ТС] 20
Сделал, теперь коды ответа вообще супер быстро получаю. А во сколько потоков это делается?
И ещё, я сейчас поставил получение кодов в бесконечный цикл, чтобы посмотреть не банит ли меня сервер. Так вот, после 2000 раз у меня уже 2 раз вылезает AggregateException. Если просто нажать на продолжить, то всё продолжается. Что делать? Как это обработать?
0
22.04.2013, 20:06
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.04.2013, 20:06

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

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

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


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

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

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