Компьютерный форум
Правила
Вернуться   Компьютерный форум > Форум программистов > Программирование под Windows > .NET
Перезагрузить страницу (C# 4.0, Многопоточность) Сумма массива + прогресс бар
Ответ
 
Опции темы Опции просмотра
  (#1 (permalink)) Старый
AndOr AndOr вне форума
Member
 
Сообщений: 24
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 24.10.2009
По умолчанию (C# 4.0, Многопоточность) Сумма массива + прогресс бар - 06.12.2011, 14:38

Здравствуйте все,

Впервые столкнулся с мультитрэдингом, читаю книги, решаю задачку:
Разработать Win приложение выполняющеее вычисление суммы огромного массива и отображающее % вычисления этого цикла в виде бегущего ползунка.

Собственно вот что я пока имею...
Csharp Код:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

// For MultiThreading
using System.Threading.Tasks;
using System.Diagnostics;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        static ulong sumTotal;
        static byte[] iArray;

        public Form1()
        {
            // initializing
            InitializeComponent();
            sumTotal = 0;
            iArray = new byte[1000000];
            for (int i = 0; i < iArray.Length; i++) iArray<i> = 1;
        }

        static void sumArray(int i)
        {
            sumTotal = sumTotal + iArray[i];
        }

        private void cbt_Start_Click(object sender, EventArgs e)
        {
            // resetting values
            progressBar.Value = 0;
            sumTotal = 0;

            // performing operations
            Stopwatch sw = new Stopwatch(); // declare timer

            tbox_OutputMulti.AppendText(">>> Started regular calculation\n");

            sw.Start(); // start timer

            int modder = iArray.Length / 100;
            for (int i = 0; i < iArray.Length; i++)
            {
                sumTotal = sumTotal + iArray[i];
                if (i % modder == 0)
                {
                    progressBar.Value = progressBar.Value + 1;
                }
            }

            sw.Stop(); // stop timer

            tbox_OutputMulti.AppendText("<<< Ended regular calculation, it took " + sw.Elapsed.TotalSeconds + " seconds. Result: " + sumTotal + "\n");

            sw.Reset(); // reset timer
            sumTotal = 0;
        }

        private void cbt_MultiThread_Click(object sender, EventArgs e)
        {
            // resetting values
            progressBar.Value = 0;
            sumTotal = 0;

            // performing operations
            Stopwatch sw = new Stopwatch(); // declare timer

            tbox_OutputMulti.AppendText(">>> Started PARALLEL calculation\n");

            sw.Start(); // start timer

            Parallel.For(0, iArray.Length, sumArray); // parallel summation of elements

            sw.Stop(); // stop timer

            tbox_OutputMulti.AppendText("<<< Ended PARALLEL calculation, it took " + sw.Elapsed.TotalSeconds + " seconds. Result: " + sumTotal + "\n");

            sw.Reset(); // reset timer
            sumTotal = 0;
        }
    }
}

Для тестирования я изначально использую массив из 1.000.000 элементов, все из них равны 1. Таким образом, сумма также должна быть 1.000.000.

На форме я сделал две кнопки:
(1) cbt_Start_Click
Выполняет обычное суммирование элементов, один за другим, также показывает процент в прогресс баре.

(2) cbt_MultiThread_Click
Тут я пытаюсь использовать метод sumArray запихную его в Parallel.For. Прогресс бар пока не пытался прикручивать.

Обе процедуры используют Stopwatch чтобы отследить время выполнения задачи. Весь вывод печатается в tbox_OutputMulti.

У меня такая проблема
Кнопка(1) работает как задумано.
А вот кнопка(2) по непонятной пока мне причине часто выдаёт неверный результат.
Далее пример вывода:
Цитата:
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 0,0295958 seconds. Result: 1000000
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 0,0210987 seconds. Result: 754586
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 0,033487 seconds. Result: 1000000
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 0,0284707 seconds. Result: 743865
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 0,0278425 seconds. Result: 748014

>>> Started regular calculation
<<< Ended regular calculation, it took 0,0160725 seconds. Result: 1000000
>>> Started regular calculation
<<< Ended regular calculation, it took 0,0160864 seconds. Result: 1000000
>>> Started regular calculation
<<< Ended regular calculation, it took 0,0160129 seconds. Result: 1000000
...
ну итд

Видно, что PARALLEL иногда возвращает 1.000.000, как и надо, но 3 из 5 результатов около 750.000. Хотелось бы узнать почему...

Ниже пример с всего 100 элементов в массиве.

(у меня ещё есть кнопка, которая заполняет массив рандомными значениями, но я её вырезал из кода)

Цитата:
>>> Started regular calculation
<<< Ended regular calculation, it took 0,0006405 seconds. Result: 100

>>> Started PARALLEL calculation
<<< Ended regular calculation, it took 6,64E-05 seconds. Result: 100

--- Filling array with new random values
--- Done filling array

>>> Started regular calculation
<<< Ended regular calculation, it took 0,0005105 seconds. Result: 13018
>>> Started regular calculation
<<< Ended regular calculation, it took 0,0005164 seconds. Result: 13018
>>> Started regular calculation
<<< Ended regular calculation, it took 0,0005725 seconds. Result: 13018

>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 0,0048328 seconds. Result: 13018
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 0,000364 seconds. Result: 13018
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 6,1E-05 seconds. Result: 13018
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 6,24E-05 seconds. Result: 13018
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 6,58E-05 seconds. Result: 13018
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 6,57E-05 seconds. Result: 13018
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 7,38E-05 seconds. Result: 13018
>>> Started PARALLEL calculation
<<< Ended PARALLEL calculation, it took 6,8E-05 seconds. Result: 13018
Тут видно, что обе кнопки каждый раз работают правильно.


Помогите разобраться где я накосячил, плиз! =)

Заранее спасибо!
Ответить с цитированием
  (#2 (permalink)) Старый
Alexiski Alexiski вне форума
Любитель давать советы
 
Сообщений: 4,281
Сказал(а) спасибо: 27
Поблагодарили 54 раз(а) в 54 сообщениях
Регистрация: 16.10.2005
По умолчанию 06.12.2011, 15:32

А почему Вы считаете, что этот код должен работать правильно?
Никто не обещал, что Parallel.for будет как-то пытаться синхронизировать запись в общие переменные
Ответить с цитированием
  (#3 (permalink)) Старый
AndOr AndOr вне форума
Member
 
Сообщений: 24
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 24.10.2009
По умолчанию 06.12.2011, 16:37

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

Т.е. можно как-то синхронизировать эту запись? Или надо вообще по-другому реализовывать?

Подскажите пожалуйста лучший вариант по вашему мнению.
И ещё хотелось бы совета по прикручиванию прогресс бара ко второй кнопке.

Спасибо за ответ Alexiski ! =)
Ответить с цитированием
  (#4 (permalink)) Старый
AndOr AndOr вне форума
Member
 
Сообщений: 24
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 24.10.2009
По умолчанию 07.12.2011, 00:20

В общем я использовал мьютекс для синхронизации.
Теперь параллельный метод хоть и работает намного медленнее, но даёт верный результат.

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

Да, что было сделано:
1) в классе объявлен мьютекс
Csharp Код:
static Mutex MtxXx = new Mutex();
2) распараллеливаемый код "заключён" в операции взятия/освобождения мьютекса
Csharp Код:
static void sumArray(int i)
{
    MtxXx.WaitOne();
    sumTotal = sumTotal + iArray[i];
    MtxXx.ReleaseMutex();
}

Последний раз редактировалось AndOr; 07.12.2011 в 00:28
Ответить с цитированием
  (#5 (permalink)) Старый
Alexiski Alexiski вне форума
Любитель давать советы
 
Сообщений: 4,281
Сказал(а) спасибо: 27
Поблагодарили 54 раз(а) в 54 сообщениях
Регистрация: 16.10.2005
По умолчанию 07.12.2011, 07:44

Цитата:
Сообщение от AndOr Посмотреть сообщение
распараллеливаемый код "заключён" в операции взятия/освобождения мьютекса
Боюсь, так Вы потеряете всё преимущество распараллеливания..

Вот тут написано, как это делать кошерно: How to: Write a Parallel.For Loop That Has Thread-Local Variables
Но я этот пример не разбирал
Ответить с цитированием
Ads.
  (#6 (permalink)) Старый
AndOr AndOr вне форума
Member
 
Сообщений: 24
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 24.10.2009
По умолчанию 07.12.2011, 11:41

Ага, спасибо большое за ссылку.

Переписал по аналогии с примером из статьи - работает в разы быстрее и даёт верный результат. Отлично.

Но как же прикрутить сюда обновление ползунка я всё никак не придумаю...

Последний раз редактировалось AndOr; 07.12.2011 в 21:59
Ответить с цитированием
  (#7 (permalink)) Старый
Alexiski Alexiski вне форума
Любитель давать советы
 
Сообщений: 4,281
Сказал(а) спасибо: 27
Поблагодарили 54 раз(а) в 54 сообщениях
Регистрация: 16.10.2005
По умолчанию 08.12.2011, 17:23

Updating a progress bar from inside a Parallel.For

И похожих тем там много, погуглите по ключевым словам Parallel.for progress
Ответить с цитированием
  (#8 (permalink)) Старый
AndOr AndOr вне форума
Member
 
Сообщений: 24
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 24.10.2009
По умолчанию 09.12.2011, 11:47

Alexiski
Я кстати конечно же гуглил, даже ещё до того, как на форум написать, но ничего не нашёл. А всё потому что не догадался по-английски поискать )))
Спасибо за ссылку.

Я попробовал вчера вечером присобачить... Получилась странная хренотень...
Теперь PARALLEL снова работает намнооого медленнее (когда последовательное вычисление занимает сотые доли секунды, параллельное - более пяти секунд, без прогресс бара - примерно одинаково). К тому же, сначала считается значение, на экран выводится сообщение что работа завершена за 5 секунд, результат такой-то. И только после этого неспеша начинает ползти заполнение прогресс бара, которое длится ещё секунд 5 =)
Я не очень понял почему так вышло, буду копаться дальше...
Ответить с цитированием
Ads
Ответ

Опции темы
Опции просмотра

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

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


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Сумма элементов массива в восьмеричном представлении [C++] druger Задания за деньги 3 20.02.2012 11:57
Сумма элементов массива Stiker_534 Assembler 0 29.05.2011 19:48
Многопоточность на С++ Merzaffka Вопросы начинающих программистов 0 07.04.2011 15:11
Функция равна сумма по i от 1 до N сумма по j от 2 до N lni/lnj marinevladi Lisp 4 12.11.2010 14:20
Многопоточность и GUI Scorpion .NET 2 28.09.2010 00:37
Работа с прогресс-баром Виталик 1 Delphi 7 11.08.2008 22:21
Прогресс бар в отдельном потоке Андрейка C. Visual C++ 9 16.11.2006 20:06
Прогресс бар сканирование диска kelz Мысли вслух 9 21.10.2006 11:43
Показ прогресса закачки файла при помощи прогресс бара Василий петрович Visual C++ 4 15.01.2006 10:04
Как можно из одного потока управлять прогресс баром в диалоге в другом imported_YETI Вопросы начинающих программистов 2 23.07.2005 01:39
Gеремещения файлов с использованием своего прогресс индикатора MoveFile Anonymous Visual C++ 2 01.10.2003 17:31



Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Нardforum.ru - компьютерный форум и программирование, форум программистов