Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.78/18: Рейтинг темы: голосов - 18, средняя оценка - 4.78
6 / 6 / 4
Регистрация: 27.05.2010
Сообщений: 48

Как увеличить скорость вычислений 500 000 строк?

30.03.2013, 23:53. Показов 3785. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Вопрос к людям с опытом. Как ускорить вычисления 500 000 строк. Задача посчитать, какую прибыль приносил магазин в среднем в день за месяц, т.е сумма прибыли за месяц / кол-во дней когда магазин работал. Имеется 600 магазинов, по которым получается список из более 20 000 строк (магазин, год, месяц), с продажами за день получается список из 500 000 строк (магазин, год, месяц, день, продажи).
Результаты применение распараллеливания расчётов, оказались неудовлетворительным прирост в скорости на 30 сек. С 1600 сек (без многопоточности) до 1570 сек (многопоточность). А неудовлетворительны потому, что в ексэле такая операция при построении сводной таблицы занимает секунды. Вот и вопрос "Как ускорить вычисление?".
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
 
namespace PohojMagaz
{
    class Magazin : IEquatable<Magazin>
    {
        public Magazin(){}
        public Magazin(string NameStore, ushort Year, byte Month, DateTime dataTime, double SalesRub)
        {
            this.NameStore = NameStore;
            this.Year = Year;
            this.Month = Month;
            this.dataTime = dataTime;
            this.SalesRub = SalesRub;
        }
        public string NameStore { get; set; }
        public ushort Year { get; set; }
        public byte Month { get; set; }
        public DateTime dataTime = new DateTime();
        public double SalesRub { get; set; }
 
        public bool Equals(Magazin other)
        {
 
            //Check whether the compared object is null.
            if (Object.ReferenceEquals(other, null)) return false;
 
            //Check whether the compared object references the same data.
            if (Object.ReferenceEquals(this, other)) return true;
 
            //Check whether the products' properties are equal.
            return NameStore.Equals(other.NameStore) && Year.Equals(other.Year) && Month.Equals(other.Month) && dataTime.Equals(other.dataTime)
                && SalesRub.Equals(other.SalesRub);
        }
 
        // If Equals() returns true for a pair of objects 
        // then GetHashCode() must return the same value for these objects.
 
        public override int GetHashCode()
        {
 
            //Get hash code for the Name field if it is not null.
            int hashMagazinNameStore = NameStore == null ? 0 : NameStore.GetHashCode();
 
            //Get hash code for the Code field.
            int hasMagazinYear = Year.GetHashCode();
            int hasMagazinMonth = Month.GetHashCode();
            int hasMagazindataTime = dataTime.GetHashCode();
            int hasMagazindataSalesRub = SalesRub.GetHashCode();
 
            //Calculate the hash code for the product.
            return hasMagazinYear ^ hashMagazinNameStore ^ hasMagazinMonth ^ hasMagazindataTime ^ hasMagazindataSalesRub;
        }
 
    }
    class Program
    {
        
        static void Main(string[] args)
        {
            Console.WriteLine("Чтение файла");
            List<Magazin> fail = new List<Magazin>();
            using (var str = new StreamReader("1.txt", Encoding.UTF8))
            {
                string s;
                int z = 0;
                while ((s = str.ReadLine()) != null)
                {
                    z++;
                    if (z > 1)
                    {
                        string[] sPod = s.Split('\t');
                        fail.Add(new Magazin());
                        fail.Last().NameStore = sPod[0];
                        fail.Last().Year = Convert.ToUInt16(sPod[1]);
                        fail.Last().Month = Convert.ToByte(sPod[2]);
                        fail.Last().dataTime = Convert.ToDateTime(sPod[3]);
                        fail.Last().SalesRub = sPod[4] == "" ? 0 : Convert.ToDouble(sPod[4].Replace(',','.'));
                    }
                }
            }
 
            
            // Получаем список магазинов для анализа
            List<string> nameStore = fail.Select(r => r.NameStore).Distinct().ToList();
            List<ushort> year = fail.Select(r => r.Year).Distinct().ToList();
            List<byte> month = fail.Select(r => r.Month).Distinct().ToList();
 
            Console.WriteLine("Убрать повторяющиеся");
            //Оставить уникальные значение (магазин, год, месяц)
            List<Magazin> storeAvgDey = new List<Magazin>();
            storeAvgDey = fail.AsParallel().Select(r => new Magazin(r.NameStore, r.Year, r.Month, new DateTime(), 0)).Distinct().ToList();
 
            //Рассчитываем какую прибыль приносил магазин, в среднем, в день за месяц
            Console.WriteLine("Расчёт среднего магазина");
            Parallel.ForEach(storeAvgDey, M =>
                                              {
                                                  M.SalesRub =
                                                      fail.AsParallel().Where(
                                                          w =>
                                                          w.NameStore == M.NameStore & w.Month == M.Month &
                                                          w.Year == M.Year).Select(
                                                              r => r.SalesRub).Average();
                                              });
 
            //Console.WriteLine("Поиск похожих магазинов");
 
            //Console.WriteLine("Вывод в файл");
            //using (var stream = new StreamWriter("Результат.txt"))
            //{
 
            //}
            Console.WriteLine("Готово");
        }
    }
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.03.2013, 23:53
Ответы с готовыми решениями:

ReadProcessMemory: как увеличить скорость сканирования памяти
Имеется такой вот код: for (uint i = 0x15000000; i &lt;= 0x29000000; i=i+4) { ReadProcessMemory(proc.Handle,(IntPtr) i, buffer, 4,...

Массивы элементов. Как увеличить скорость создания?
В VB6 я создавал массив элементов (кнопок) следующим образом: помещал на форму кнопку и указывал, что она будет входить в массив кнопок....

Истекло время ожидания запроса после вставки 500 000 — 700 000 записей
С помошью цикла заносится в БД миллион с лишним строк. for (; i &lt; count_lns; i++) { dp.Insert(dp.Conn, into_tablename,...

4
713 / 680 / 126
Регистрация: 30.03.2012
Сообщений: 1,124
31.03.2013, 02:14
C#
1
2
3
w =>
w.NameStore == M.NameStore & w.Month == M.Month &
w.Year == M.Year).
сколько раз по вашему вы выполняете этот участок кода?
правильный ответ - 10 миллиардов раз
магазинов в списке
C#
1
storeAvgDey = fail.AsParallel().Select(r => new Magazin(r.NameStore, r.Year, r.Month, new DateTime(), 0)).Distinct().ToList();
20 тысяч (см. 1 сообщение темы), элементов в листе fail - 500 тысяч (см. 1 сообщение темы) т.е. для каждого из 20 тысяч магазинов вы проверяете 500 тысяч элементов в листе fail
вы уверены что все 10 миллиардов итераций нужны?

как бы эту проблему попробовал решить я:
1) изменить объектную структуру - разделить объект магазин на два:
а) собственно магазин, имеющий название, год, месяц и лист продаж за день
б) продажи за день - имеющие день и сумму в рублях
магазин будет идентифицироваться по первым трем полям (название, год, месяц)
2) вместо инициализации листа fail на 500 тысяч позиций я бы создал Dictionary магазинов, при чтении новой строки из потока добавлял бы продажи к магазинам (если магазина в словаре нет - добавлял бы магазин и добавлял бы к нему продажу)
на выходе из первого цикла я бы получил словарь в котором содержатся магазины (20 тыщ штук) каждый из которых содержит лист продаж за день (суммарно 500 тыщ штук)
3) все что нам нужно дальше это пробежаться по словарю и для каждого из 20 тысяч магазинов посчитать сумму в листе продаж за день итоговое количество проходов по этому циклу будет 500 тысяч вместо 10 миллиардов

ну и кстати вот это место:
C#
1
storeAvgDey = fail.AsParallel().Select(r => new Magazin(r.NameStore, r.Year, r.Month, new DateTime(), 0)).Distinct().ToList();
создает 500 тысяч новых объектов, а потом 480 тысяч из них выкидывает, на месте сборщика мусора я бы ругался матом вместо того чтобы рассказать методу Distinct как именно нужно сравнивать объекты (не учитывая поле даты) вы создаете 500 тысяч новых объектов

надеюсь оптимизации последнего цикла в двадцать тысяч раз вам хватит ^_^

Добавлено через 14 минут
более простой способ оптимизации цикла (если лениво писать первый)
1) ДО цикла сгруппировать лист fail по указанным параметрам (groupby)
вы получите 20 тысяч групп в которых будет суммарно 500 тысяч объектов
потом в цикле получать группу по ключу и считать элементы
число проходов тоже будет 500 тысяч вместо 10 миллионов (за счет того что вы не будете группировать объекты каждый раз)
2
Заблокирован
31.03.2013, 13:46
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
 class Magazin
    {
        public Magazin() { }
        public Magazin(string NameStore, ushort Year, byte Month, DateTime dataTime, double SalesRub)
        {
            this.NameStore = NameStore;
            this.Year = Year;
            this.Month = Month;
            this.dataTime = dataTime;
            this.SalesRub = SalesRub;
        }
        public string NameStore { get; set; }
        public ushort Year { get; set; }
        public byte Month { get; set; }
        public DateTime dataTime = new DateTime();
        public double SalesRub { get; set; }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            List<Magazin> fail = new List<Magazin>(){ 
                new Magazin(){ 
                    dataTime=DateTime.Now, //Дата, неясно зачем тогда поле Year
                    Month=1, //Месяц
                     NameStore="A", //Наверно имя магазина
                      SalesRub=12.34, //Суммарная прибыль за месяц
                       Year=1983 //год
                },
                 new Magazin(){ 
                    dataTime=DateTime.Now, 
                    Month=2,
                     NameStore="B",
                      SalesRub=6,
                       Year=1983
                },
                 new Magazin(){ 
                    dataTime=DateTime.Now, 
                    Month=1,
                     NameStore="B",
                      SalesRub=12,
                       Year=1983
                }
            };
 
           //Посчитать, для каждого магазина среднюю прибыль за месяц в каждом году
            var result1 = from mag in fail.AsParallel()
                          group mag by new { mag.Year, mag.NameStore } into g
                          let sum = from spMag in g.AsParallel()
                                    select spMag.SalesRub
                          select new { NameMag = g.Key.NameStore, Year=g.Key.Year, Avg = sum.Average() };
 
 
            //Посчитать, для каждого магазина среднюю прибыль за день
            var result2 = from mag in fail.AsParallel()
                          select new { NameMag = mag.NameStore, Month = mag.Month, Year = mag.Year, Avg = mag.SalesRub / 30D };
        }
    }
Добавлено через 2 часа 5 минут
Цитата Сообщение от RANLOD Посмотреть сообщение
Здравствуйте. Вопрос к людям с опытом. Как ускорить вычисления 500 000 строк. Задача посчитать, какую прибыль приносил магазин в среднем в день за месяц, т.е сумма прибыли за месяц / кол-во дней когда магазин работал. Имеется 600 магазинов, по которым получается список из более 20 000 строк (магазин, год, месяц), с продажами за день получается список из 500 000 строк (магазин, год, месяц, день, продажи).
[/CSHARP]
C#
1
2
3
4
5
6
7
  new Magazin(){ 
                    dataTime=DateTime.Now, //День продажи, один из 30
                    Month=1, //Месяц текущий
                     NameStore="A", //Магазин
                      SalesRub=12, //Суммарная прибыль за день
                       Year=1980 //год
                },
C#
1
2
3
4
5
6
7
8
9
10
11
    //Посчитать среднюю прибыль в день, за месяц, для каждого магазина, для каждого месяца, для каждого года
            var result1 = from mag in fail.AsParallel()
                          group mag by new { mag.Year, mag.NameStore,mag.Month } into g
                          let sum = from spMag in g.AsParallel()
                                    select spMag.SalesRub
                          select new { NameMag = g.Key.NameStore, Month=g.Key.Month, Year=g.Key.Year, Avg = sum.Average() };
 
           //Вывести
            foreach (var res in result1)
                Console.WriteLine(String.Concat("Магазин "+res.NameMag," в ",res.Year," году "," за ",res.Month," месяц имел среднюю прибыль в день ",res.Avg," грн."));
                Console.ReadKey();
1
 Аватар для HIMen
4340 / 1509 / 101
Регистрация: 12.04.2009
Сообщений: 2,342
31.03.2013, 16:03
Покажи файл
0
6 / 6 / 4
Регистрация: 27.05.2010
Сообщений: 48
01.04.2013, 10:11  [ТС]
Реализовал как подсказал Tessen стало действительно выполнятся за секунду. Только при использовании параллельного ForEach происходит ошибка "Индекс находился вне границ массива.". Это не столь критично, но интересно с чем это может быть связано? Вот сам код:
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
 
namespace PohojMagaz
{
    //Ключ пользовательского типа данных(несколько ключей Dictionary)
    class Magazin : IEquatable<Magazin>
    {
        public Magazin(){}
        public Magazin(string NameStore, ushort Year, byte Month)
        {
            this.NameStore = NameStore;
            this.Year = Year;
            this.Month = Month;
        }
        public string NameStore { get; set; }
        public ushort Year { get; set; }
        public byte Month { get; set; }
 
        public bool Equals(Magazin other)
        {
 
            //Check whether the compared object is null.
            if (Object.ReferenceEquals(other, null)) return false;
 
            //Check whether the compared object references the same data.
            if (Object.ReferenceEquals(this, other)) return true;
 
            //Check whether the products' properties are equal.
            return NameStore.Equals(other.NameStore) && Year.Equals(other.Year) && Month.Equals(other.Month);
        }
 
        // If Equals() returns true for a pair of objects 
        // then GetHashCode() must return the same value for these objects.
 
        public override int GetHashCode()
        {
 
            //Get hash code for the Name field if it is not null.
            int hashMagazinNameStore = NameStore == null ? 0 : NameStore.GetHashCode();
 
            //Get hash code for the Code field.
            int hasMagazinYear = Year.GetHashCode();
            int hasMagazinMonth = Month.GetHashCode();
 
            //Calculate the hash code for the product.
            return hasMagazinYear ^ hashMagazinNameStore ^ hasMagazinMonth;
        }
 
    }
    class Program
    {
        
        static void Main(string[] args)
        {
            Console.WriteLine("Чтение файла");
            Dictionary<Magazin,List<double>> fail = new Dictionary<Magazin, List<double>>();
            using (var str = new StreamReader("1.txt", Encoding.UTF8))
            {
                string s;
                int z = 0;
                while ((s = str.ReadLine()) != null)
                {
                    z++;
                    if (z > 1)
                    {
                        string[] sPod = s.Split('\t');
                        Magazin temp = new Magazin(sPod[0], Convert.ToUInt16(sPod[1]), Convert.ToByte(sPod[2]));
                        //Проверяем есть ли магазин из потока, если нет, то создаём магазин с List'ом
                        if (!fail.Keys.Contains(temp))
                        {
                            fail.Add(
                            temp,
                            new List<double>());
                            fail[temp].Add(sPod[4] == "" ? 0 : Convert.ToDouble(sPod[4]));
                        }
                        else fail[temp].Add(sPod[4] == "" ? 0 : Convert.ToDouble(sPod[4]));
                    }
                }
            }
            //Convert.ToDouble(sPod[4].Replace(',', '.')
           
                // Считаем средние продажи в день
            Dictionary<Magazin, double> storeAvgDey = new Dictionary<Magazin, double>();
            Console.WriteLine("Расчёт среднего магазина");
            //При использовании параллельного ForEach происходит ошибка "Индекс находился вне границ массива."
            //Parallel.ForEach(fail, M =>
            //                           {
            //                               storeAvgDey[M.Key] = M.Value.Average();
            //                           });
            foreach (var M in fail)
            {
                storeAvgDey[M.Key] = M.Value.Average();
            }
 
            Console.WriteLine("Поиск похожих магазинов");
 
            //Console.WriteLine("Вывод в файл");
            //using (var stream = new StreamWriter("Результат.txt"))
            //{
 
            //}
            Console.WriteLine("Готово");
        }
    }
}
Urety спасибо result1 тоже выполняется быстро.

HIMen файл большой мин размер 40 мб, шапка файла выглядит так (Наименование магазина|Год|Номер месяца|Дата|Продажи по факт.цене без НДС, руб.) ну а характеристики данных я уже описывал.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
01.04.2013, 10:11
Помогаю со студенческими работами здесь

Как увеличить скорость загрузки страницы
Сам asp-файл 200кБ. Эта страница выводит данные в таблицу(20x20) из базы(Access) 1. Влияет ли размер asp-файла на скорость загрузки? 2....

Как увеличить (оптимизировать) скорость TCP сервера?
Всем привет. Я написал свой асинхронный TCP сервер на шарпах, использую его для игры. Запускаю сервак на своем пк и запускаю 2 клиента и...

Как увеличить скорость отображения данных
Данные вывожу в datagrid, datagrid привязан к List&lt;class&gt;. В datagrid имеется 20 столбцов и нужно вывести 1000 строк, на то чтоб появились...

Как создать 1 000 000 строк без совпадений?
помогите дорогие друзья!!! как создать 1 000 000 строк без совпадений? делаю так private void button1_Click(object sender, EventArgs e)...

Как увеличить скорость работы программы?
Всем привет! Программа проходит 6/8 тестов (тесты неизвестны), а на последние 2 превышен лимит времени. Прошу помощи. Задача: ...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11680&amp;d=1772460536 Одним из. . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru