Форум программистов
 
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Вернуться   Форум программистов > .NET > C# (си шарп)
Регистрация

Восстановить пароль
Повторная активизация e-mail


Ответ
 
Опции темы
Старый 21.04.2014, 15:23   #1
L6go1as
Форумчанин
 
Регистрация: 20.10.2011
Сообщений: 453
Репутация: 39
По умолчанию Многопоточность

Добрый день Уважаемые, подскажите, как организовать отдельный поток под каждый объект в цикл ?

Хочу сделать вот такую работу:
Код:

кол-во потоков: 4

0 для потока 0
1 для потока 1
2 для потока 2
3 для потока 3
4 для потока 0
5 для потока 1
6 для потока 2 
7 для потока 3
8 для потока 0
9 для потока 1
Цикл закончен!

Реализую следующим образом:
Код:

private void button2_Click(object sender, EventArgs e)
        {
            int n = 4;
            Thread[] t = new Thread[n];
            for (int i = 0; i < n; i++)
            {
                t[i] = new Thread(test);
                t[i].Name = "Поток " + i;
                t[i].Start(i);
            }
        }

        public void test(object param)
        {
            int x = Convert.ToInt32(param);
            for (int i = x; i < 10; i++)
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    textBox1.Text += i + " для потока: " + x + Environment.NewLine;
                });
            }
                this.Invoke((MethodInvoker)delegate()
                {
                    textBox1.Text += "Цикл закончен!" + Environment.NewLine;
                });
        }

Но в к сожалению данный код работает не корректно.
Думаю можно ручками прописать выполнение цикла под разные потоки, к примеру:
Код:

t[0].Start(test_1), где цикл for будет от 0 до 3
t[1].Start(test_2), где цикл for будет от 4 до 7
t[2].Start(test_3), где цикл for будет от 8 до 9

Но разве это выход ?

Последний раз редактировалось L6go1as; 21.04.2014 в 16:06.
L6go1as вне форума   Ответить с цитированием
Старый 21.04.2014, 19:40   #2
L6go1as
Форумчанин
 
Регистрация: 20.10.2011
Сообщений: 453
Репутация: 39
По умолчанию

Подобрал 2 варианта:

"ручной":
Код:

int n = 3;
Thread[] t = new Thread[n];

 t[0] = new Thread(() =>
            {
                for (int i = 0; i < 4; i++)
                {
                    this.Invoke((MethodInvoker)delegate()
                       {
                           textBox1.Text += i + " для потока: 0" + Environment.NewLine;
                       });
                }
            });
            t[0].Start();

            t[1] = new Thread(() =>
            {
                for (int i = 4; i < 8; i++)
                {
                    this.Invoke((MethodInvoker)delegate()
                    {
                        textBox1.Text += i + " для потока: 1" + Environment.NewLine;
                    });
                }
            });
            t[1].Start();

            t[2] = new Thread(() =>
            {
                for (int i = 8; i < 10; i++)
                {
                    this.Invoke((MethodInvoker)delegate()
                    {
                        textBox1.Text += i + " для потока: 2" + Environment.NewLine;
                    });
                }
            });
            t[2].Start();

ThreadPool:
Код:

for (int i = 0; i < 10; i++)
            {
                int q = i;
                
                ThreadPool.QueueUserWorkItem((x) =>
                {
                    this.Invoke((MethodInvoker)delegate()
                    {
                        textBox1.Text += q + Environment.NewLine;
                    });
                });
            }

Или можно вообще не замарачиваться и записать так:
Код:

ThreadPool.QueueUserWorkItem(test)

И вот пару вопросиков:

Первый вариант работает, но уж больно "в лоб", можно ли как ни будь упростить ?
Второй вариант работает тоже, но вот не понятно, насколько это производительный вариант и работает ли он оптимально, и насколько "лучшим" вариантом является ? Использовал ThreadPool.GetAvailableThreads, он мне выдает тысячу доступных потоков и тысячу потоков асинхронного ввода\вывода, насколько я понимаю то система резервирует ресурсы под все эти потоки, не слишком ли дорого для системы ?

Последний раз редактировалось L6go1as; 21.04.2014 в 20:08.
L6go1as вне форума   Ответить с цитированием
Старый 22.04.2014, 09:14   #3
Guy
Форумчанин
 
Регистрация: 15.12.2010
Адрес: yaroslavl
Сообщений: 398
Репутация: 129
По умолчанию

Однозначно используйте пул потоков, он даст наибольший прирост производительности и свидёт к минимуму переключения контекстов.
Guy вне форума   Ответить с цитированием
Старый 22.04.2014, 10:23   #4
Пепел Феникса
Модератор
Заслуженный модератор
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Адрес: Москва
Сообщений: 21,006
Репутация: 3402

icq: 446843180
skype: phoenix_proger
По умолчанию

Цитата:
Использовал ThreadPool.GetAvailableThreads, он мне выдает тысячу доступных потоков и тысячу потоков асинхронного ввода\вывода, насколько я понимаю то система резервирует ресурсы под все эти потоки, не слишком ли дорого для системы ?
это сколько можно выделить потоков, изначально они не созданы конечно, и не жрут ничего.
__________________
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума   Ответить с цитированием
Старый 22.04.2014, 11:36   #5
L6go1as
Форумчанин
 
Регистрация: 20.10.2011
Сообщений: 453
Репутация: 39
По умолчанию

Ясно, буду тогда в сторону Пула смотреть, однако пока не удается решить поставленную задачу ...

Код:

int threads = 4;

        private void button2_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < threads; i++)
            {
                ThreadPool.QueueUserWorkItem(test, i);
            }
            
            textBox1.Text = "В работе..." + Environment.NewLine;
        }
        void test(object thread)
        {
            for (int i = 0; i < 100; i++)
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    textBox1.Text += i + " Запущен: " + thread + Environment.NewLine;
                });
            }
        }

/*Все работает, но выдает:
0 Запущен: 0
0 Запущен: 2
0 Запущен: 1
0 Запущен: 3
1 Запущен: 0
1 Запущен: 2
1 Запущен: 1
1 Запущен: 3
2 Запущен: 0
2 Запущен: 2
2 Запущен: 1
2 Запущен: 3 и т.д.*/

Код:

for (int i = 0; i < 100; i++)
            {
                int q = i;

                ThreadPool.QueueUserWorkItem((x) =>
                    {
                        this.Invoke((MethodInvoker)delegate()
                        {
                            textBox1.Text += q + " Запущен: " + Environment.NewLine;
                        });
                    });
            }
/*Все работает, но выдает:
0 Запущен: 
2 Запущен: 
1 Запущен: 
4 Запущен: 
3 Запущен: 
5 Запущен: и т.д.*/

Если в первом коде я сам установил что будет работать 4 потока, но они работают одновременно и над одной задачей - чего быть не должно, почему так происходит не могу понять ...

Второй код работает "как надо", однако совершенно не понятно сколько потоков на выполнением трудились, если работает лишь одно, то смысл использовать пул )

Есть ли возможность отследить сколько потоков работает для второго кода ?
Или можно ли как нить пофиксить первый, что бы очередность работы сохранялась ?
L6go1as вне форума   Ответить с цитированием
Старый 22.04.2014, 14:05   #6
L6go1as
Форумчанин
 
Регистрация: 20.10.2011
Сообщений: 453
Репутация: 39
По умолчанию

Хм, в поисках решения дошел до Parallel.For и похоже этот вариант наилучший.
Код:

var watch = Stopwatch.StartNew();
            int z = 0;
            watch.Start();
            Parallel.For(0, 500, i =>
            {
                z = i * 2;
            });
            watch.Stop();
            textBox1.Text = "Summa: " + z + " Parallel.For: " 
                + watch.Elapsed.TotalMilliseconds.ToString() + Environment.NewLine;

            int w = 0;
            watch.Start();
            for (int i = 0; i < 500; i++)
            {
                int q = i;
                ThreadPool.QueueUserWorkItem((x) =>
                {
                    w = q * 2;
                });
            }
            watch.Stop();
            textBox1.Text += "Summa: " + w + " ThreadPool: " 
                + watch.Elapsed.TotalMilliseconds.ToString() + Environment.NewLine;

Результаты следующие:
Код:

Summa: 998 Parallel.For: 0.8198
Summa: 998 ThreadPool: 3.4681

Однако сумма для ThreadPool не всегда совпадает с суммой в Parallel.For, почему так происходит ? И почему такая дикая разница в методах ? (Ведь по идее TP должен работать быстрее)
L6go1as вне форума   Ответить с цитированием
Ответ

Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
С++ многопоточность kineziz Общие вопросы C/C++ 3 11.09.2012 13:20
многопоточность blacktener Общие вопросы по Java, Java SE, Kotlin 1 25.07.2012 13:18
Многопоточность t2skler Общие вопросы C/C++ 4 16.04.2012 14:24
многопоточность Freddi Krjuger Общие вопросы по Java, Java SE, Kotlin 1 15.05.2011 23:46
Многопоточность Dezmont_ Общие вопросы .NET 1 06.11.2010 19:34


01:44.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru