Как увеличить скорость вычислений 500 000 строк? - C#
Формулировка задачи:
Здравствуйте. Вопрос к людям с опытом. Как ускорить вычисления 500 000 строк. Задача посчитать, какую прибыль приносил магазин в среднем в день за месяц, т.е сумма прибыли за месяц / кол-во дней когда магазин работал. Имеется 600 магазинов, по которым получается список из более 20 000 строк (магазин, год, месяц), с продажами за день получается список из 500 000 строк (магазин, год, месяц, день, продажи).
Результаты применение распараллеливания расчётов, оказались неудовлетворительным прирост в скорости на 30 сек. С 1600 сек (без многопоточности) до 1570 сек (многопоточность). А неудовлетворительны потому, что в ексэле такая операция при построении сводной таблицы занимает секунды. Вот и вопрос "Как ускорить вычисление?".
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("Готово");
}
}
}Решение задачи: «Как увеличить скорость вычислений 500 000 строк?»
textual
Листинг программы
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("Готово");
}
}
}