Estaba jugando con C# y quería acelerar un programa. Hice cambios y pude hacerlo. Sin embargo, necesito ayuda para entender por qué el cambio lo hizo más rápido.Ayuda para comprender la optimización de C#
He intentado reducir el código a algo más fácil de entender en una pregunta. Score1 y Report1 es la forma más lenta. Score2 y Report2 es la forma más rápida. El primer método primero almacena una cadena y un int en una estructura en paralelo. A continuación, en un bucle en serie, recorre una matriz de esas estructuras y escribe sus datos en un búfer. El segundo método primero escribe los datos en un búfer de cadena en paralelo. A continuación, en un bucle en serie, escribe los datos de cadena en un búfer. Aquí están algunas veces muestra de ejecución:
Run 1 Total Promedio de tiempo = 0,492087 seg Run 2 Total Promedio de tiempo = 0,273619 seg
Cuando estaba trabajando con una versión anterior no paralelo a esto, los tiempos eran casi lo mismo. ¿Por qué la diferencia con la versión paralela?
Incluso si reduzco el ciclo en Informe1 para escribir una sola línea de salida en el búfer, aún es más lento (tiempo total aproximadamente .42 segundos).
Este es el código simplificado:.
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();
}
}
}
Por qué estás tratando de clasificar tales como Informe1 código diferente y Report2? Report1 contiene un bucle y Report2 no. ¿Tal vez en la versión no paralela el compilador de C# desenrolló el bucle o alguna otra magia? – Earlz
Reducir el bucle de Report1 a una iteración ayuda un poco (.42 seg), pero después de la publicación, creo que es la asignación de matriz en Score1. – jlim
Nota: la lista de palabras es de aproximadamente 14,000 líneas de cadenas. Entonces cada llamada de puntaje asigna 14,000 estructuras. – jlim