Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
 Аватар для zewer
2357 / 1775 / 212
Регистрация: 07.01.2011
Сообщений: 10,342

Эффект от применения потоков к сумированию элементов массива

12.11.2015, 02:29. Показов 2069. Ответов 33
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здраствуйте, есть массив на 100000000 элементов. В него пихаем рандомные данные типа double.
Потом считаем суму всех элементов.
Получаеться, что выполнение в главном потоке в 3 раза быстрее, чем, если бы запускать 2 потока
Почему так?
И почему результаты не совпадают в дробной части?

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
using System;
using System.Runtime;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TestLibrary;
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
 
class Program
{
    public static double suma1 = 0;
    public static double suma2 = 0;
    public static double suma = 0;
 
    static void Main(string[] args)
    {
        double[] a = new double[100000000];//наш массив
        Random rnd = new Random();
        for(int i=0; i<a.Length;i++)
        {
            a[i] = rnd.NextDouble()*rnd.Next(1000);//пихаем рандом числа в массив
        }
 
        Console.WriteLine("/******1 THREAT******/");
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Func(a);//выполняем в главном потоке
        sw.Stop();
        Console.WriteLine(sw.Elapsed);
 
        sw.Reset();
        
        Thread th1 = new Thread(() => Func1(a));//0-Длина/2
        Thread th2 = new Thread(() => Func2(a));//Длина/2 до Длины
        th1.Priority = ThreadPriority.Highest;
        th2.Priority = ThreadPriority.Highest;
        Console.WriteLine("/******MULTI THREAT******/");
        sw.Start();
        th1.Start();
        th2.Start();
        th1.Join();
        th2.Join();
        Console.WriteLine(suma1 + suma2);
        sw.Stop();
        Console.WriteLine(sw.Elapsed);
    }
 
    static void Func(double[] a)
    {
        for (int i=0; i<a.Length; i++)
        {
            suma += a[i];
        }
        Console.WriteLine(suma);
    }
 
    static void Func1(double[] a)
    {
        for (int i = 0; i < a.Length/2; i++)
        {
            suma1 += a[i];
        }
    }
    static void Func2(double[] a)
    {
        for (int i = a.Length/2; i < a.Length; i++)
        {
            suma2 += a[i];
        }
    }
}
Результат
/******1 THREAT******/
24975723278,0035
00:00:00.5711327
/******MULTI THREAT******/
24975723278,0043
00:00:01.4812455
Press any key to continue . . .
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
12.11.2015, 02:29
Ответы с готовыми решениями:

Ошибка из-за применения массива
Работаю с файлом *.xls через OpenOffice Calc. На форме 2 элемента RadioButton1 и RadioButton2. Если выбрать RadioButton1 дважды, то все...

Как обратиться к элементам массива БЕЗ применения индексов
Есть динамический массив А. Поменять местами максимальный элемент главной и побочной диагоналей с элементом, расположенным на пересечении...

Связка массива структур с классом без применения указателей
У меня такая задача по учебе: Написать программу с использованием объектно-ориентированных технологий. Количество созданных классов –...

33
Кодогенератор
 Аватар для hepper
200 / 200 / 51
Регистрация: 15.06.2011
Сообщений: 794
12.11.2015, 23:07
Студворк — интернет-сервис помощи студентам
вот запуск вашего кода в релизрежиме без отладчика
Миниатюры
Эффект от применения потоков к сумированию элементов массива  
1
 Аватар для zewer
2357 / 1775 / 212
Регистрация: 07.01.2011
Сообщений: 10,342
13.11.2015, 00:54  [ТС]
Цитата Сообщение от hepper Посмотреть сообщение
вот запуск вашего кода в релизрежиме без отладчика
интересно, перекомпилил у себя в релиз, все равно потоки медленее, но правда и 1 потоки, и 2 потоки, начали решать задачу заметно быстрее (0.38 мейн поток и 0.9 2 потока)
какой у вас ЦП?
0
Кодогенератор
 Аватар для hepper
200 / 200 / 51
Регистрация: 15.06.2011
Сообщений: 794
13.11.2015, 02:53
Цитата Сообщение от zewer Посмотреть сообщение
какой у вас ЦП?
intel i3

Добавлено через 1 минуту
zewer, проект запускаете вне студии?
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,576
13.11.2015, 04:09
У меня оригинальный код вот так отрабатывает (процессор i5 760)

Дебаг
/******1 THREAT******/
24978151125,4456
00:00:00.4555566
/******MULTI THREAT******/
24978151125,4492
00:00:00.3876151
Релиз
/******1 THREAT******/
24971355256,1778
00:00:00.3076760
/******MULTI THREAT******/
24971355256,1722
00:00:00.1615313
0
484 / 397 / 68
Регистрация: 14.02.2014
Сообщений: 1,930
13.11.2015, 10:22
А вот ещё любопытный момент:
набросал dll на плюсах имеющую одну функцию суммирования элементов массива, подключил её к шарповскому проекту и сравнил все варианты. Результаты:
Creating time: 4292 ms
By FOR elapsed 586 ms, sum = 24972089786,1658
By FOREACH elapsed 570 ms, sum = 24972089786,1658
By LINQ elapsed 657 ms, sum = 24972089786,1658
By PLINQ elapsed 379 ms, sum = 24972089786,1774
By TASKS elapsed 2013 ms, sum = 24972089786,1775
By C++ elapsed 150 ms, sum = 24972089786,1658
Добавлено через 1 минуту
Камень АМД А10-7700К, 4 ядра.
В студии: конечная платформа х86, релизная сборка, оптимизация включена.
0
-39 / 2 / 1
Регистрация: 21.09.2015
Сообщений: 58
13.11.2015, 11:34
Результат сортировки массива с библиотекой BindingAndServiceCoreParellel.

...N.............1 thread............8 Core
1000...............0.01.............0.19 ..........x = 0.05
10.000............0.56..............0.47 .........x = 1.19
50.000...........14.38.............3.90. .........x = 3.68
100.000..........57.34...........12.88.. ........x = 4.45
300.000........8.37.17........1.38.56... .......x = 6.00
500.000......24.02.64.........4.24.32... .......x = 5.65



C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// для одного потока
           TimeSpan difference;
           DateTimeOffset dateOffset1, dateOffset2;
  
             int N=500000;
             int[] IntArray = new  int[N];
             Random random = new Random();
             for(int i=0; i <  N; i++){ IntArray[i]= random. Next ();}
             dateOffset1 = DateTimeOffset.Now;  
             int max, index,k;
             for(int i=0 ; i< N; i++)
              { max= IntArray[i]; index=i;
                for (int j=i; j<N; j++)
                  {if(max >= IntArray[j]) continue;
                   max= IntArray[j];  index=j;
                  }                  
                   k = IntArray[i]; IntArray[i]=IntArray[index]; IntArray[index]=k;
             } 
 
              dateOffset2 = DateTimeOffset.Now;
              difference= dateOffset2 -dateOffset1;
              MessageBox.Show("Время  теста  " +difference.ToString());
0
13.11.2015, 11:50

Не по теме:

Тотальное отсутствие у человека логики. Это печально.

0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
13.11.2015, 13:04
Лучший ответ Сообщение было отмечено zewer как решение

Решение

zewer,

Во-первых, результат теста очень зависит от методики тестирования. Вот вы, к примеру, тестируя суммирование массива зачем-то в обоих случаях включили в замер еще и вывод результата на консоль, но при этом не посчитали время на создание потоков, которое может быть значительным.

Во-вторых, вы по сути тестируете не один и тот же метод, но распараллеленный, а два разных подхода к задаче, и проблема здесь в оптимизаторе: в первом случае у вас идет цикл от 0 до длины массива. Оптимизатор обучен засекать такие циклы и вырезать из генерируемого кода проверки на выходы за пределы массива. Во втором случае у вас переменная цикла высчитывается (деление на 2), потому оптимизатор здесь ничего не делает и на каждой итерации вставляет проверку — не вышел ли массив за пределы.

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

Вот тот же самый код, но всего лишь малость измененный с учетом вышеперечисленного:
1. В однопоточном случае убрана фора в виде вырезанной проверки индексов. Как вариант для уравновешивания можно использовать небезопасный код во втором случае, чтобы избавиться от проверки, но просто убрать оптимизацию проще в плане реализации.
2. Из замера времени убран вывод в консоль в обоих случаях.
3. Во втором случае так же учитывается время на создание потоков.
4. В многопоточный код добавлен учет кэша процессора в виде локальной переменной, куда пишется сумма. Статическая переменная записывается только один раз после цикла. Для честности то же самое сделано в однопоточном методе.

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
using System;
using System.Runtime;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
 
class Program
{
    public static double suma1 = 0;
    public static double suma2 = 0;
    public static double suma = 0;
 
    static void Main(string[] args)
    {
        double[] a = new double[100000000];//наш массив
        Random rnd = new Random();
        for (int i = 0; i < a.Length; i++)
        {
            a[i] = rnd.NextDouble() * rnd.Next(1000);//пихаем рандом числа в массив
        }
 
        Console.WriteLine("/******1 THREAT******/");
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Func(a, 0, a.Length);//выполняем в главном потоке
        sw.Stop();
        Console.WriteLine(suma);
        Console.WriteLine(sw.Elapsed);
 
        sw.Reset();
 
        
        Console.WriteLine("/******MULTI THREAT******/");
        sw.Start();
        Thread th1 = new Thread(() => Func1(a));//0-Длина/2
        Thread th2 = new Thread(() => Func2(a));//Длина/2 до Длины
        th1.Priority = ThreadPriority.Highest;
        th2.Priority = ThreadPriority.Highest;
        th1.Start();
        th2.Start();
        th1.Join();
        th2.Join();
        var sum = suma1 + suma2;
        sw.Stop();
        Console.WriteLine(sum);
        Console.WriteLine(sw.Elapsed);
    }
 
    static void Func(double[] a, int start, int length)
    {
        int count = start + length;
        double sum = 0;
        for (int i = start; i < count; i++)
        {
            sum += a[i];
        }
        suma = sum;
    }
 
    static void Func1(double[] a)
    {
        double sum = 0;
        for (int i = 0; i < a.Length / 2; i++)
        {
            sum += a[i];
        }
        suma1 = sum;
    }
    static void Func2(double[] a)
    {
        double sum = 0;
        for (int i = a.Length / 2; i < a.Length; i++)
        {
            sum += a[i];
        }
        suma2 = sum;
    }
}
Результат работы под релизным билдом без отладчика:


В первом методе многопоточного способа, кстати, еще можно убрать деление длины массива на 2 на каждой итерации, ну да бог с ним.
2
484 / 397 / 68
Регистрация: 14.02.2014
Сообщений: 1,930
13.11.2015, 13:17
kolorotur, шикарно, я даже как-то не подумал, что использование глобальных переменных затормозит потоки. В своём варианте дополнительно убрал деление длинны архива пополам из цикла в переменную. Результат:
Creating time: 4238 ms
By FOR elapsed 578 ms, sum = 24977254588,6183
By FOREACH elapsed 568 ms, sum = 24977254588,6183
By LINQ elapsed 662 ms, sum = 24977254588,6183
By PLINQ elapsed 332 ms, sum = 24977254588,6293
By TASKS elapsed 99 ms, sum = 24977254588,6272
By C++ elapsed 150 ms, sum = 24977254588,6183
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
13.11.2015, 13:30
Цитата Сообщение от aquaMakc Посмотреть сообщение
я даже как-то не подумал, что использование глобальных переменных затормозит потоки.
Ну это не общий принцип, а просто конкретный случай, так как:
1. Статическая переменная и массив живут в куче
2. Массив большой.
3. В кэш процессора память помещается сплошным блоком по принципу "если идет запрос к этому адресу, то, возможно, будут запросы к адресам поблизости".

Из этого следует, что на ранних итерациях с большой вероятностью и статическая переменная и кусок массива попадут в кэш, т.к. в программе между их созданием происходит немного и скорее всего они лежат где-то рядом.
А вот на поздних итерациях им обоим в кэше уже не быть, т.к. интервал памяти между переменной и обрабатываемым в данный момент куском массива будет больше, чем размер кэша. Вот процессор и будет метаться от одного к другому.
В случае с локальной переменной джиттер увидит, что эта переменая мало того, что локальная, так еще и часто используется в цикле и с большой вероятностью поместит эту переменную сразу в регистр процессора, а не в стэк или кучу.
Вот, кстати, почему-то любители порассуждать о том, где хранятся переменные: в стэке или в куче, почему-то всегда забывают про регистры
0
13.11.2015, 15:42

Не по теме:

Цитата Сообщение от Dedoc Посмотреть сообщение
Результат сортировки массива с библиотекой BindingAndServiceCoreParellel.
Тебя просили привести код с использованием твоей библиотеки. Без этого ни код ни бенчмарки не имеют смысла.

Кроме этого для замера времени исполнения следует использовать Stopwatch из-за более низкой погрешности по сравнению с DateTime/DateTimeOffset.

0
 Аватар для zewer
2357 / 1775 / 212
Регистрация: 07.01.2011
Сообщений: 10,342
13.11.2015, 17:43  [ТС]
Тестил свой код на AMD Phenom II x4 965 3,7 GHz
Перетестил на другом компе на базе Intel Core 2 Quad 9505 2,83 Ghz, и там потоки заметно быстрее выполнились чем один мейн поток
Может феном не дружит с потоками дот нета?

Добавлено через 5 минут
kolorotur, спасибо, прошел у себя
С вашим кодом мой феном 965 быстрее мотает чем Q9505
Результат с 965 фенома, в релизе, и общий прирост в потоках, по сравнению с мейн потоком, теперь равен почти 2 раза

/******1 THREAT******/
24973075111,8512
00:00:00.1701636
/******MULTI THREAT******/
24973075111,8488
00:00:00.0950845
Press any key to continue . . .
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
13.11.2015, 20:26
OwenGlendower, для этого вообще стоит использовать специальные библиотеки, высчитывающие погрешность, прогревающие кэш и прочее...

Я обычно юзаю BenchmarkDotNet (небольшая реклама ), с недавних пор в её разработке участвует Джон Скит (хотя я начал ей пользоваться еще до этого), что косвенно говорит о том, что либа довольно интересная. Ну и я позволили себе добавить для сравнения еще и свою реализацию.
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
using System;
using System.Linq;
using BenchmarkDotNet;
using XLinq;
 
namespace BenchApp
{
    public class Tester
    {
        private double[] _a;
        private double EtalonSum;
 
        public Tester()
        {
            double[] a = new double[64*1024*1024];//наш массив
            Random rnd = new Random();
            for (int i = 0; i < a.Length; i++)
            {
                a[i] = rnd.NextDouble() * rnd.Next(1000);//пихаем рандом числа в массив
            }
            _a = a;
            EtalonSum = Enumerable.Sum(a);
        }
 
        [Benchmark]
        public void SingleThread()
        {
            double sum = 0;
            foreach (double d in _a)
            {
                sum += d;
            }
            if (Math.Abs(sum - EtalonSum) > 1)
                throw new Exception();
        }
 
        [Benchmark]
        public void MultiThread()
        {
            double sum = _a.AsParallel().Sum();
            if (Math.Abs(sum - EtalonSum) > 1)
                throw new Exception();
        }
 
        [Benchmark]
        public void MultiThreadXLinq()
        {
            double sum = _a.Sum();
            if (Math.Abs(sum - EtalonSum) > 1)
                throw new Exception();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var runner = new BenchmarkRunner();
            runner.RunCompetition(new Tester());
        }
    }
}
Миниатюры
Эффект от применения потоков к сумированию элементов массива  
0
13.11.2015, 23:08

Не по теме:

Цитата Сообщение от Psilon Посмотреть сообщение
Я обычно юзаю BenchmarkDotNet
Я тоже :) Отличная библиотека.

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
13.11.2015, 23:08

Последнее значение массива x, после применения функции обращается в 0
#include &lt;stdio.h&gt; #include &lt;math.h&gt; double fun1(const double x); double fun2(const double x); void transform(const double...

Как реализовать код без применения ассоциативного массива (map)?
Имеется такой код. Как можно его изменить, не использую массив map? #include &lt;iostream&gt; #include &lt;map&gt; #include &lt;string&gt; ...

Как правильно вывести строку двухмерного массива без применения цикла
Подскажите пожалуйста, вот я обьявляю строку char s; Если Мне нужен массив строк, то я обьявляю его s Как дальше использоваь второй...

Как сделать эффект размытия (эффект стекла) в Xaml?
Как сделать эффект размытия(эффект стекла) в Xaml?

Необходимо разработать функцию, вычисляющую среднее арифметическое массива (без применения рекурсии)
Не получается написать программку.&quot;Символ используется для хранения индексированных данных (аналогично массиву). Свойство Length содержит...


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

Или воспользуйтесь поиском по форуму:
34
Ответ Создать тему
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru