Stavo giocando con C# e volevo accelerare un programma. Ho apportato delle modifiche e sono riuscito a farlo. Tuttavia, ho bisogno di aiuto per capire perché il cambiamento lo ha reso più veloce.Aiuto alla comprensione dell'ottimizzazione C#
Ho tentato di ridurre il codice a qualcosa di più facile da capire in una domanda. Score1 e Report1 sono il modo più lento. Score2 e Report2 è il modo più veloce. Il primo metodo memorizza dapprima una stringa e un int in una struct in parallelo. Successivamente, in un ciclo seriale, scorre in una matrice di quelle strutture e scrive i loro dati in un buffer. Il secondo metodo scrive prima i dati in un buffer di stringhe in parallelo. Successivamente, in un ciclo seriale, scrive i dati della stringa in un buffer. Qui ci sono alcuni tempi di esecuzione del campione:
Run 1 Totale Media Time = 0,492,087 mila sec Run 2 Tempo complessivo medio = 0,273,619 mila sec
Quando lavoravo con una versione precedente non paralleli di questo, i tempi erano quasi lo stesso. Perché la differenza con la versione parallela?
Anche se riduco il loop in Report1 per scrivere una singola riga di output nel buffer, è ancora più lento (tempo totale circa, 42 secondi).
Ecco il codice semplificato.
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();
}
}
}
Perché stai cercando di rango come codice diverso come Report1 e Report2? Report1 contiene un loop e Report2 no. Forse nella versione non parallela il compilatore C# ha srotolato il loop o qualche altra magia? – Earlz
Ridurre il loop Report1 a una iterazione aiuta un po '(.42 sec), ma dopo la pubblicazione, penso che sia l'allocazione dell'array in Score1. – jlim
Nota: l'elenco di parole contiene circa 14.000 righe di stringhe. Quindi ogni chiamata di score1 alloca 14.000 strutture. – jlim