[英]Linq Optimization for Count And Group By
我已經寫了一個代碼來計算二進制文件中每個字節的頻率。 使用Linq。 執行Linq表達式時,代碼似乎變慢。 在這種邏輯上似乎很難實現並行。 要構建超過475MB的頻率表,大約需要1分鍾。
class Program
{
static void Main(string[] args)
{
Dictionary<byte, int> freq = new Dictionary<byte, int>();
Stopwatch sw = new Stopwatch();
sw.Start();
//File Size 478.668 KB
byte[] ltext = File.ReadAllBytes(@"D:\Setup.exe");
sw.Stop();
Console.WriteLine("Reading File {0}", GetTime(sw));
sw.Start();
Dictionary<byte, int> result = (from i in ltext
group i by i into g
orderby g.Count() descending
select new { Key = g.Key, Freq = g.Count() })
.ToDictionary(x => x.Key, x => x.Freq);
sw.Stop();
Console.WriteLine("Generating Freq Table {0}", GetTime(sw));
foreach (var i in result)
{
Console.WriteLine(i);
}
Console.WriteLine(result.Count);
Console.ReadLine();
}
static string GetTime(Stopwatch sw)
{
TimeSpan ts = sw.Elapsed;
string elapsedTime = String.Format("{0} min {1} sec {2} ms",ts.Minutes, ts.Seconds, ts.Milliseconds);
return elapsedTime;
}
我嘗試使用幾個循環來實現non linq解決方案,其性能大致相同。 請提出任何優化建議。 對不起,我的英語不好
在我那本笨拙的戴爾筆記本電腦上的442MB文件上,這花了一點時間:
byte[] ltext = File.ReadAllBytes(@"c:\temp\bigfile.bin");
var freq = new long[256];
var sw = Stopwatch.StartNew();
foreach (byte b in ltext) {
freq[b]++;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
很難擊敗數組的原始性能。
在發布模式下構建時,以下顯示在9秒鍾內我機器上465MB文件中字節的降序顯示。
請注意,我通過以100000字節的塊讀取文件來提高了速度(您可以對此進行試驗-16K塊對我的機器沒有明顯的影響)。 關鍵是內部循環是一個提供字節的循環。 調用Stream.ReadByte()的速度很快,但不及索引數組中的字節的速度快。
同樣,將整個文件讀入內存會施加極大的內存壓力,這會影響性能,並且如果文件足夠大,則將完全失敗。
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
class Program
{
static void Main( string[] args )
{
Console.WriteLine( "Reading file..." );
var sw = Stopwatch.StartNew();
var frequency = new long[ 256 ];
using ( var input = File.OpenRead( @"c:\Temp\TestFile.dat" ) )
{
var buffer = new byte[ 100000 ];
int bytesRead;
do
{
bytesRead = input.Read( buffer, 0, buffer.Length );
for ( var i = 0; i < bytesRead; i++ )
frequency[ buffer[ i ] ]++;
} while ( bytesRead == buffer.Length );
}
Console.WriteLine( "Read file in " + sw.ElapsedMilliseconds + "ms" );
var result = frequency.Select( ( f, i ) => new ByteFrequency { Byte = i, Frequency = f } )
.OrderByDescending( x => x.Frequency );
foreach ( var byteCount in result )
Console.WriteLine( byteCount.Byte + " " + byteCount.Frequency );
}
public class ByteFrequency
{
public int Byte { get; set; }
public long Frequency { get; set; }
}
}
為什么不只是
int[] freq = new int[256];
foreach (byte b in ltext)
freq[b]++;
?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.