【发布时间】:2014-06-17 15:37:18
【问题描述】:
我有一个从 100 万到甚至 1 亿个整数的大型整数列表。
我想按出现次数对它们进行排名,并选择最热门的K(此处为K=10)结果。
我已经尝试了 4 种不同的方法,其中我的 Method1 是最快的。并行化并没有超过我自己在Method1 中的分组代码,并且由于线程竞争条件导致排名不准确。
Method1 和 Method4 的结果准确无误,而 Method2 和 Method3 可能由于比赛条件而排名不准确。
现在,我正在寻找比 Method1 更快的任何可能的代码,或者对并行化方法的修复,使其准确,然后比 Method1 更快。
class Benchmark
{
static List<int> input = new List<int>();
static void Main(string[] args)
{
int count = int.Parse(args[0]);
Random rnd = new Random();
for (int i = 0; i < count; i++)
input.Add(rnd.Next(1, count));
DoBench();
Console.ReadKey();
}
private static void DoBench()
{
for (int i = 1; i <= 4; i++)
{
DateTime start = DateTime.Now;
List<KeyValuePair<int, int>> results = null;
switch (i)
{
case 1:
results = Method1();
break;
case 2:
results = Method2();
break;
case 3:
results = Method3();
break;
case 4:
results = Method4();
break;
}
int resultsCount = 10;
var topResults = results.Take(resultsCount).OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToArray();
for (int j = 0; j < resultsCount; j++)
Console.WriteLine("No {0,2}: {1,8}, Score {2,4}", j + 1, topResults[j].Key, topResults[j].Value);
Console.WriteLine("Time of Method{0}: {1} ms", i, (long)DateTime.Now.Subtract(start).TotalMilliseconds);
Console.WriteLine();
}
}
private static List<KeyValuePair<int, int>> Method1()
{
Dictionary<int, int> dic = new Dictionary<int, int>();
for (int i = 0; i < input.Count; i++)
{
int number = input[i];
if (dic.ContainsKey(number))
dic[number]++;
else
dic.Add(number, 1);
}
var sorted_results = dic.OrderByDescending(x => x.Value).ToList();
return sorted_results;
}
private static List<KeyValuePair<int, int>> Method2()
{
var sorted_results = input.AsParallel().GroupBy(x => x)
.Select(g => new KeyValuePair<int, int>(g.Key, g.Count()))
.OrderByDescending(x => x.Value).ToList();
return sorted_results;
}
private static List<KeyValuePair<int, int>> Method3()
{
ConcurrentDictionary<int, int> dic = new ConcurrentDictionary<int, int>();
input.AsParallel<int>().ForAll((number) =>
{
dic.AddOrUpdate(number, 1, new Func<int, int, int>((key, oldValue) => oldValue + 1));
});
var sorted_results = dic.OrderByDescending(x => x.Value).ToList();
return sorted_results;
}
private static List<KeyValuePair<int, int>> Method4()
{
var sorted_results = input.GroupBy(x => x)
.Select(g => new KeyValuePair<int, int>(g.Key, g.Count()))
.OrderByDescending(x => x.Value).ToList();
return sorted_results;
}
}
【问题讨论】:
-
所以?你的
Method1对你来说慢吗?您是否正在寻找 2/3 的修复程序?您是否有目标要如何改进直方图+排序方法? (我认为您现在无法获得像 1 中那样紧凑和可读的任何东西,.Net 中没有可以帮助排序的堆,并且将源拆分为范围以修复并行版本将需要更多的行和可能不会加快速度) -
@AlexeiLevenkov,对不起,我忘了说我的目标。是的,我的 Method1 对于我的场景来说很慢,因为它将被执行数千次。以及使并行版本更快的任何可能的修复
-
我会尝试 map-reduce... 按 CPU 数量(即 1-999,1000-1999)将数组拆分为连续范围,计算单独的直方图(无锁定),然后合并生成的直方图在单线程中。比排序(或找到 heap 实现以获得 Top(N) 结果)...请注意,只有当您的数据集相对较小(如您的情况)并且访问数据没有额外成本时才有意义(例如它已经在内存中,没有磁盘/网络 IO)。
-
如果您使用没有 AsParallel() 的方法 2,是否有积极的区别?在我看来,AsParallel 只是造成了开销。
-
@CSharpie,你是对的。我正在寻找一个准确的并行化版本,但在实践中还没有工作......
标签: c# performance list