Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

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

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

Купить рекламу на форуме - 42 тыс руб за месяц

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

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

Хочу сделать вот такую работу:
Код:
кол-во потоков: 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
Сообщений: 433
По умолчанию

Подобрал 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
Сообщений: 398
По умолчанию

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

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

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

Код:
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
Сообщений: 433
По умолчанию

Хм, в поисках решения дошел до 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 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
С++ многопоточность 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 18:34