我在玩C#並希望加快一個程序。我做了改變,並能夠這樣做。但是,我需要幫助理解爲什麼變化更快。幫助理解C#優化
我試圖減少代碼,以更容易理解的問題。 Score1和Report1是較慢的方法。 Score2和Report2是更快的方法。第一種方法首先在並行結構中存儲一個字符串和一個int。接下來,在一個串行循環中,它循環遍歷這些結構的數組並將它們的數據寫入緩衝區。第二種方法首先將數據並行寫入字符串緩衝區。接下來,在串行循環中,它將字符串數據寫入緩衝區。下面是一些樣品運行時間:
運行1總平均時間= 0.492087秒 運行2總平均時間= 0.273619秒
當我隨着早期非水貨版的這個工作,時間幾乎一樣。爲什麼與平行版本有所不同?
即使我減少Report1中的循環以將單行輸出寫入緩衝區,它仍然較慢(總時間約爲.42秒)。
這裏是簡化代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using System.IO;
namespace OptimizationQuestion
{
class Program
{
struct ValidWord
{
public string word;
public int score;
}
ValidWord[] valid;
StringBuilder output;
int total;
public void Score1(string[] words)
{
valid = new ValidWord[words.Length];
for (int i = 0; i < words.Length; i++)
{
StringBuilder builder = new StringBuilder();
foreach (char c in words[i])
{
if (c != 'U')
builder.Append(c);
}
if (words[i].Length == 3)
{
valid[i] = new ValidWord
{ word = builder.ToString(), score = words[i].Length };
}
}
}
public void Report1(StringBuilder outputBuffer)
{
int total = 0;
foreach (ValidWord wordInfo in valid)
{
if (wordInfo.score > 0)
{
outputBuffer.AppendLine(String.Format("{0} {1}", wordInfo.word.ToString(), wordInfo.score));
total += wordInfo.score;
}
}
outputBuffer.AppendLine(string.Format("Total = {0}", total));
}
public void Score2(string[] words)
{
output = new StringBuilder();
total = 0;
for (int i = 0; i < words.Length; i++)
{
StringBuilder builder = new StringBuilder();
foreach (char c in words[i])
{
if (c != 'U')
builder.Append(c);
}
if (words[i].Length == 3)
{
output.AppendLine(String.Format("{0} {1}", builder.ToString(), words[i].Length));
total += words[i].Length;
}
}
}
public void Report2(StringBuilder outputBuffer)
{
outputBuffer.Append(output.ToString());
outputBuffer.AppendLine(string.Format("Total = {0}", total));
}
static void Main(string[] args)
{
Program[] program = new Program[100];
for (int i = 0; i < program.Length; i++)
program[i] = new Program();
string[] words = File.ReadAllLines("words.txt");
Stopwatch stopwatch = new Stopwatch();
const int TIMING_REPETITIONS = 20;
double averageTime1 = 0.0;
StringBuilder output = new StringBuilder();
for (int i = 0; i < TIMING_REPETITIONS; ++i)
{
stopwatch.Reset();
stopwatch.Start();
output.Clear();
Parallel.ForEach<Program>(program, p =>
{
p.Score1(words);
});
for (int k = 0; k < program.Length; k++)
program[k].Report1(output);
stopwatch.Stop();
averageTime1 += stopwatch.Elapsed.TotalSeconds;
GC.Collect();
}
averageTime1 /= (double)TIMING_REPETITIONS;
Console.WriteLine(string.Format("Run 1 Total Average Time = {0:0.000000} sec", averageTime1));
double averageTime2 = 0.0;
for (int i = 0; i < TIMING_REPETITIONS; ++i)
{
stopwatch.Reset();
stopwatch.Start();
output.Clear();
Parallel.ForEach<Program>(program, p =>
{
p.Score2(words);
});
for (int k = 0; k < program.Length; k++)
program[k].Report2(output);
stopwatch.Stop();
averageTime2 += stopwatch.Elapsed.TotalSeconds;
GC.Collect();
}
averageTime2 /= (double)TIMING_REPETITIONS;
Console.WriteLine(string.Format("Run 2 Total Average Time = {0:0.000000} sec", averageTime2));
Console.ReadLine();
}
}
}
爲什麼你試圖排名這樣不同的代碼爲報表和報告2? Report1包含一個循環,Report2不包含。也許在非並行版本中,C#編譯器展開了循環或其他魔法? – Earlz 2011-02-09 05:32:27
將Report1循環減少爲一次迭代有一點幫助(.42秒),但發佈後,我認爲它是Score1中的數組分配。 – jlim 2011-02-09 05:35:52
注意:單詞列表大約是14,000行字符串。因此,每次調用score1分配14,000個結構。 – jlim 2011-02-09 06:02:11