Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# .NET
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
awp-sirius
58 / 58 / 41
Регистрация: 01.05.2012
Сообщений: 496
1

И снова многопоточность

01.06.2014, 02:13. Просмотров 1362. Ответов 36
Метки нет (Все метки)

Доброй ночи всем!

Я уже понял, что это ооочень заезженная тема "многопоточность")

Полностью просмотрел урок (2 часа) http://www.youtube.com/watch?v=strsTAfcAv4

Основы-то понял, но как именно реализовать мою задачу пока не совсем понимаю...
А задача в следующем:
Имеется какой-то длинный массив строк. Ну и используем к примеру 10 потоков.

Должно происходить что-то следующее:
1-й поток берёт себе 1-ю строку массива, 2-й вторую и так далее. НО время выполнения может быть разное, и если первые 9 потоков ещё выполняют задачу, а 10-й поток уже выполнил мвою 10-ю строку, то он должен брать следующую строку массива (11-ю).
И так соответственно все остальные. (Не блещу умением объяснять))

Короче: что бы когда поток выполняет какое-то действие с элементом массива, он должен брать следующий первый попавшийся.

Сложность с тем, что бы 2 потока не взяли один и тот же элемент...

Весь день читаю статьи и не могу точно найти ответ на поставленную задачу. И при помощи чего делать..
Почему-то кажется что подойдёт пул потоков.. Или может через Parallel.For?

Скорее всего буду делать WidowsForms, поэтому может быть использовать BackgroundWorker?..

В общем подскажите пожалуйста... Уже очень долго мучаюсь..

P.S. Заранее отвечу на вопрос, программа ProxyChecker.. Просто встала задача под определённый сайт. Саму проверку прокси уже реализовал, вот теперь мучаюсь, что бы ускорить сее творение.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.06.2014, 02:13
Ответы с готовыми решениями:

многопоточность
Привет подскажите возможно ли отслеживать проникновение посторонних программ...

Многопоточность
Собсно захотел,что бы пакет отправлялся с разных прокси в разных потоках....

Многопоточность
Есть массив, заполненный случайными числами, на 500 элементов.Есть textBox1 и...

Многопоточность и ЦП
Вызвал метод в контексте 2х вторичных потоков(основной поток + 2 вторичных) и...

Многопоточность
Как сделать много поточность? т.е. 1 поток отвечает за отправку запроса на...

36
Psilon
Master of Orion
Эксперт .NET
6000 / 4850 / 902
Регистрация: 10.07.2011
Сообщений: 14,460
Записей в блоге: 5
Завершенные тесты: 4
01.06.2014, 19:43 21
Лучший ответ Сообщение было отмечено awp-sirius как решение

Решение

awp-sirius, Parallel гарантирует именно ту модель поведения, которую вы предлагаете.
Он создает N потоков и дает им первые N элементов на обработку. Если какой-то поток закончил работу, то ему дается следующий по очереди элемент массива. И так до тех пор, пока массив не кончится. Один "быстрый" поток может сделать 3 задачи, в то время как один "медленный" выполнит тем делом только одну. Только вот не принимайте разработчиков за дураков, они не стали бы делать АПИ, которым никто не стал бы пользоваться, а если бы был возможен доступ к одному элементу массива дважды, так оно и было бы.

ThreadPool.SetMaxThreads(int workerThreads, int completionPortThreads), но что такое int completionPortThreads?
На msdn написано, но как-то не понятно..
Этот метод вообще лучше не трогайте. Задавать максимальное число потоков нужно так:
C#
1
 Parallel.For(1, 100, new ParallelOptions {MaxDegreeOfParallelism = 4}, Console.WriteLine); //Использовать не более 4 потоков
1
Winhttp22
151 / 122 / 22
Регистрация: 16.02.2013
Сообщений: 820
01.06.2014, 21:06 22
Цитата Сообщение от Psilon Посмотреть сообщение
вручную, это new Thread()
а какие это... преимущества что ли, у пула, от ручного создания потоков? В пуле можно потоки завершать? Я знаю, что нельзя Создавал уже тему - Потоки не сразу убиваются (или так надо?) , сейчас программы у меня работают через "костыль" - остановка потоков происходит лишь "визуально", и они еще работают некоторое время, если попадется прокси сервер медленный. А как жить то?

Цитата Сообщение от Psilon Посмотреть сообщение
Только вот не принимайте разработчиков за дураков, они не стали бы делать АПИ, которым никто не стал бы пользоваться, а если бы был возможен доступ к одному элементу массива дважды, так оно и было бы.
так почему бы тогда не использовать сторонние либы, написанные другими разработчиками? Ну к примеру - xNet, Viking.Engine(о которой не очень хорошие отзывы тру кодеров)?
0
awp-sirius
58 / 58 / 41
Регистрация: 01.05.2012
Сообщений: 496
01.06.2014, 21:36  [ТС] 23
Psilon, Огромное спасибо, выручаете меня уже не первый раз!

Только вот проблема с переменными...
Как я понял там, где у вас написано "Console.WriteLine" пишется метод, который выполняется для текущего числа (в вашем примере от 1 до 100). Для меня тоесть это номер сроки массива.


Но, когда выполняется вторичный поток он знает только № этой строки, а само значение из массива извлечь не может..
Как мне передать в метод Check сам массив string[] NewProxy = richTextBox1.Lines.ToArray()?
Так же проблема наоборот. Если прокси валидный, нужно его записать в richTextBox2, а там ошибка мол richTextBox2 создан в другом потоке.
На сколько понимаю это делается как-то при помощи Invoke, но на этом знание заканчивается....

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
public Form1()
        {
            InitializeComponent();
        }
 
        string[] Proxy;
 
        public void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Enabled = false;
 
            
            string[] NewProxy = richTextBox1.Lines.ToArray();
 
            
            Parallel.For(0, NewProxy.Length, new ParallelOptions { MaxDegreeOfParallelism = 10 }, Check);
 
            richTextBox1.Enabled = true;
        }
 
 
        static void Check(int i)
        {
            using (var Request = new HttpRequest())
            {
                try
                {
                    Request.CharacterSet = System.Text.Encoding.GetEncoding("UTF-8");
                    Request.Proxy = HttpProxyClient.Parse(NewProxy[i]);
                    string SourcePage = Request.Get("http://auto.ru").ToString();
                    string logo = SourcePage.Substrings("<img id=\"logo-pic\" src=\"", "\" width=\"79\" height=\"19", 0)[0];
 
                    if (logo == "http://i.auto.ru/design/2012/img/autoru-logo-i.png")
                    {
                        //richTextBox2.Text += NewProxy[i] + "\n";
                        MessageBox.Show("Прокси валид");
                    }
                }
                catch
                {
                    MessageBox.Show("Прокси невалид");
                }
 
 
            }
 
        }
Добавлено через 2 минуты
естественно проблема на 29 строке

Добавлено через 6 минут
с выводом вроде разобрался:

C#
1
this.richTextBox2.Text = i + "\n";
Добавлено через 13 минут
Хотя нет... Не разобрался. Запись-то идёт, но иногда выскакивает ошибка мол обращение из 2-х потоков...
lock как-то не помогает почему-то =(

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
object block = new object();
 
        public Form1()
        {
            InitializeComponent();
        }
 
        public void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Enabled = false;
            
            string[] NewProxy = richTextBox1.Lines.ToArray();
            
            Parallel.For(0, NewProxy.Length, new ParallelOptions { MaxDegreeOfParallelism = 10 }, Print);
 
            richTextBox1.Enabled = true;
        }
 
        public void Print(int i)
        {
            lock (block)
            {
                this.richTextBox2.Text += i + "\n";
            }
        }
0
Winhttp22
151 / 122 / 22
Регистрация: 16.02.2013
Сообщений: 820
01.06.2014, 22:18 24
Цитата Сообщение от awp-sirius Посмотреть сообщение
Хотя нет... Не разобрался. Запись-то идёт, но иногда выскакивает ошибка мол обращение из 2-х потоков...
Control.Invoke Method (Delegate)
0
Psilon
Master of Orion
Эксперт .NET
6000 / 4850 / 902
Регистрация: 10.07.2011
Сообщений: 14,460
Записей в блоге: 5
Завершенные тесты: 4
01.06.2014, 23:32 25
awp-sirius, используй Parallel.ForEach вместо Parallel.For

Цитата Сообщение от Winhttp22 Посмотреть сообщение
а какие это... преимущества что ли, у пула, от ручного создания потоков? В пуле можно потоки завершать? Я знаю, что нельзя Создавал уже тему - Потоки не сразу убиваются (или так надо?) , сейчас программы у меня работают через "костыль" - остановка потоков происходит лишь "визуально", и они еще работают некоторое время, если попадется прокси сервер медленный. А как жить то?
Потоки как правило не нужно завершать А преимущества - то, что слишком много потоков - вся производительность будет убиваться на переключение контекста. В общем почитайте, зачем вообще нужны "пулы" объектов, что потоков, что памяти, что чего-нибудь еще
0
Winhttp22
151 / 122 / 22
Регистрация: 16.02.2013
Сообщений: 820
02.06.2014, 00:20 26
Цитата Сообщение от Psilon Посмотреть сообщение
Потоки как правило не нужно завершать
ну это не всегда.
Цитата Сообщение от Psilon Посмотреть сообщение
В общем почитайте, зачем вообще нужны "пулы" объектов, что потоков, что памяти, что чего-нибудь еще
да, нужно почитать, подтянуть знания Правда мне не жаловались пока на плохую производительность программ . Но если производительность станет лучше - то почему бы и нет?))
0
Psilon
Master of Orion
Эксперт .NET
6000 / 4850 / 902
Регистрация: 10.07.2011
Сообщений: 14,460
Записей в блоге: 5
Завершенные тесты: 4
02.06.2014, 00:53 27
Winhttp22, просто нет смысла делать хуже, если лучше сделать не сложнее

ну это не всегда.
остановку потока легко можно сделать внутри метода поточного. Thread.Abort() вообще считается редскостной какашкой, и абсолютно не рекомендуется его использовать. Ну а без него разницы нет, а та, что есть, не в тему Thread'а

http://stackoverflow.com/questions/1...g-thread-abort

Добавлено через 2 минуты
советую прочитать все ответы целиком, но краткая выдержка от Эрика:
In short, Thread.Abort is at best indicative of bad design, possibly unreliable, and extremely dangerous. It should be avoided at all costs; the only time you should ever even consider aborting a thread is in some sort of "emergency shutdown" code where you are attempting to tear down an appdomain as cleanly as possible.
0
awp-sirius
58 / 58 / 41
Регистрация: 01.05.2012
Сообщений: 496
02.06.2014, 01:15  [ТС] 28
Не могу въехать.....

ForEach<TSource>(IEnumerable<TSource>, Action<TSource, ParallelLoopState>)
Что там есть что.. Везде написано мудрёно...

Можно хотя бы пример как сделать из

C#
1
2
3
4
5
string[] NewProxy = richTextBox1.Lines.ToArray();
            foreach (string i in NewProxy)
            {
                richTextBox2.Text += i + "\n";
            }
Тоже самое, только многопотоковое Parallel.ForEach. Пусть даже будет не по порядку.....
0
Psilon
Master of Orion
Эксперт .NET
6000 / 4850 / 902
Регистрация: 10.07.2011
Сообщений: 14,460
Записей в блоге: 5
Завершенные тесты: 4
02.06.2014, 01:30 29
awp-sirius,
C#
1
2
string[] text = "Что там есть что.. Везде написано мудрёно... Можно хотя бы пример как сделать из".Split();
Parallel.ForEach(text, s => Console.WriteLine(s));
Добавлено через 1 минуту
awp-sirius, блин, забудьте про текстбоксы и прочее. Вся многопоточность должна работать с внутренними списками и массивами, и не обращаться к элементам формы. В лучшем случае получете ошибку "доступ к компоненту не из потока, в котором он был создан", а в худшем - трудноуловимый баг.
0
awp-sirius
58 / 58 / 41
Регистрация: 01.05.2012
Сообщений: 496
02.06.2014, 01:49  [ТС] 30
Psilon, Получается список валидных прокси можно будет получить только по окончанию всей проверки...
А как тогда делают подобные программы? Каждый проверенный сразу появляется в текстбоксе..
Может подключить BackgroungWorker?

Добавлено через 12 минут
Почему вот таким способом не получается сделать?...

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
        object block = new object();
 
        public void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Enabled = false;
 
            string[] NewProxy = richTextBox1.Lines.ToArray();
            Parallel.ForEach(NewProxy, new ParallelOptions { MaxDegreeOfParallelism = 10 }, s => { Print(s); });
 
            richTextBox1.Enabled = true;
        }
 
        public void Print(string s)
        {
            lock (block)
            {
                richTextBox2.Text += s + "\n";
            }
        }
не срабатывает lock...
0
Psilon
Master of Orion
Эксперт .NET
6000 / 4850 / 902
Регистрация: 10.07.2011
Сообщений: 14,460
Записей в блоге: 5
Завершенные тесты: 4
02.06.2014, 01:51 31
awp-sirius, они вызывают событие. А на событие подписывается формочка, и уже сама отображает в своем потоке. Это называется ООП и принцип единой ответственности

Добавлено через 1 минуту
хотя бы так:
C#
1
2
3
4
5
6
7
8
9
10
11
        public void Print(string s)
        {
            if (InvokeRequired)
            {
                Invoke(new Action(() => Print(s)));
            }
            else
            {
                richTextBox2.Text += s + "\n";
            }
        }
0
awp-sirius
58 / 58 / 41
Регистрация: 01.05.2012
Сообщений: 496
02.06.2014, 02:46  [ТС] 32
Цитата Сообщение от Psilon Посмотреть сообщение
хотя бы так: ...........
= Если метод Print уже исполняется, то начать выполнять метод сначала?
или же записать в бокс?



Сейчас проверил... Нет.. Видно какие-то потоки зацикливаются..
После выполнения форма неактивна

Добавлено через 23 минуты
Господи, когда же я уже сделаю это.....

Добавлено через 10 секунд


Добавлено через 24 минуты
вот так вроде пашет:
C#
1
2
if (richTextBox2.InvokeRequired) richTextBox2.BeginInvoke(new Action<string>((s) => Print(s)), n);
else richTextBox2.Text += n + "\n";
только меня смущает то, что вы написали "хотя бы так:" тоесть этот способ не очень хорош?
0
EVG-1980
190 / 197 / 82
Регистрация: 11.04.2013
Сообщений: 1,086
02.06.2014, 07:28 33
Цитата Сообщение от awp-sirius Посмотреть сообщение
только меня смущает то, что вы написали "хотя бы так:" то есть этот способ не очень хорош?
Потому что Invoke прерывает выполнение потока на время вывода данных и только после этого поток продолжает свою работу
0
awp-sirius
58 / 58 / 41
Регистрация: 01.05.2012
Сообщений: 496
02.06.2014, 18:50  [ТС] 34
Подскажите, как выполнить поставленную задачу правильно?....
Мне кажется нужно всё же использовать backgroundWorker...
0
Psilon
Master of Orion
Эксперт .NET
6000 / 4850 / 902
Регистрация: 10.07.2011
Сообщений: 14,460
Записей в блоге: 5
Завершенные тесты: 4
02.06.2014, 19:10 35
awp-sirius, я же уже сказал парой постов назад Всю логику по пингу (или что там у вас) и прочему вообще желательно поместить библиотеку, в которой не должно быть никаких System.Windows.Forms и так далее. Там нужно объявить класс, который будет пинговать и по результатам этих пингов вызывать событие Ping_successed. В это время форма должна подписаться на это событие, ну а в самом событии уже с помощью BeginInvoke отображать результаты на форме.
0
awp-sirius
58 / 58 / 41
Регистрация: 01.05.2012
Сообщений: 496
02.06.2014, 22:23  [ТС] 36
Ладно если откинуть форму вообще. Список прокси из файла записываем в массив.


Просто я не понимаю.... Parallel.ForEach требует статический метод...
И как можно из него что-то куда-то записать.............?

Добавлено через 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
namespace Console_Proxy
{
    class Program
    {
        static void Main(string[] args)
        {
            StringCollection EditProxy = new StringCollection();
 
            string[] NewProxy = { "19", "8.", "27.1", "25", ".222:", "78", "08", "212.", "154.1", "54", ".220:", "80", "80", "209", ".129", ".24", "4.6:", "80" };
 
            Parallel.ForEach(NewProxy, new ParallelOptions { MaxDegreeOfParallelism = 100 }, n => Check(n, EditProxy));
 
            foreach (Object obj in EditProxy) Console.WriteLine(obj);
 
            Console.ReadLine();
        }
 
 
        static void Check(string n, StringCollection EditProxy)
        {
            if (n.Length == 4)
            {
                EditProxy.Add(n);
            }
        }
    }
}
Если честно не понимаю, почему программа не ругается на использование EditProxy из разных потоков одновременно.... Можете объяснить?
0
Spawn
971 / 869 / 353
Регистрация: 24.03.2014
Сообщений: 2,381
Записей в блоге: 2
02.06.2014, 23:35 37
Цитата Сообщение от awp-sirius Посмотреть сообщение
Просто я не понимаю.... Parallel.ForEach требует статический метод...
Ну, Вы в принципе в статическом методе находитесь, о каком экземплярном речь?)
Цитата Сообщение от awp-sirius Посмотреть сообщение
И как можно из него что-то куда-то записать.............?
События, как уже выше написали... пару раз.
Цитата Сообщение от awp-sirius Посмотреть сообщение
Если честно не понимаю, почему программа не ругается на использование EditProxy из разных потоков одновременно.... Можете объяснить?
А на что ей ругаться? Можете это хоть потокобезопасностью обозвать, не на что ей просто ругаться. Ваша коллекция в отличие от "окошек" Windows не требует DispatchMessage и очереди сообщений для нормального функционирования, так что жаловаться особо не на что. Жаловаться будет на что скорее Вам, если отсутствует синхронизация, но предполагается.
3
02.06.2014, 23:35
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.06.2014, 23:35

Многопоточность
Подскажите очень срочно нужно - сделать многопоточное приложение, в котором...

Многопоточность
В программе создается поток по обработке данных, его работа занимает приличное...

Многопоточность .NET
Приходилось на работе заниматься серверным приложением на С++, причем Win32 Com...


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

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

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