Gå til innhold

C#: [Løst]Merkelig oppførsel av List<double>


Anbefalte innlegg

Testet allokering av minne i generic List. Prøver å legge inn 10000000 int verdier i en List<int>. En burde kunne speedet opp dette hjelp av new List<int>(10000000) som forhåndallokerer plasser i arrayet. Det pussige er at det tar nesten dobbelt så lang tid! 375 ms mot 655 ms med forhåndsallokering. Looper begge beregningene 10 ganger for å vise at det ikke er oppstartsproblemer som gjør at det tar lang tid. Kan noen andre sjekke dette og se om dere får samme resultat? Noen forklaringer?

 

 

using System;
using System.Collections.Generic;
using System.Threading;

class Program
{
   static void Main()
   {
       Thread.Sleep(1000);
       for (int j = 0; j < 10; j++)
       {
           int start = Environment.TickCount;
           const int count = 10000000;
           List<int> list = new List<int>();
           for (int i = 0; i < count; i++)
           {
               list.Add(i);
           }
           Console.Out.WriteLine("Allok: OFF:" + ((double)(Environment.TickCount - start)));
           list = new List<int>(count);
           for (int i = 0; i < count; i++)
           {
               list.Add(i);
           }
           Console.Out.WriteLine("Allok:  ON:" + ((double)(Environment.TickCount - start)));
       }
       Console.ReadKey();
   }
}

 

Programeringsfeil

Endret av OleM80
Lenke til kommentar
Videoannonse
Annonse

using System;
using System.Collections.Generic;

namespace TimeTaker
{
static class Program
{
	static void Main()
	{

		List<double> list;
		int count = 10000000;

		TimerBlock timer;
		using (timer = new TimerBlock())
		{
			list = new List<double>(count);
		}
		Console.WriteLine("Time passed: " + timer.TimePassed.ToString() + " seconds");
		using (timer = new TimerBlock())
		{
			list = new List<double>();
			for (int i = 0; i < count; i++)
			{
				list.Add(0);
			}
		}
		Console.WriteLine("Time passed: " + timer.TimePassed.ToString() + " seconds"); 

	}


}

public class TimerBlock : IDisposable
{
	[System.Runtime.InteropServices.DllImport("Kernel32")]
	static extern bool QueryPerformanceCounter(ref long counter);
	[System.Runtime.InteropServices.DllImport("Kernel32")]
	static extern bool QueryPerformanceFrequency(ref long freq);

	static long GetFrequency()
	{
		long val = 0;
		QueryPerformanceFrequency(ref val);
		return val;
	}

	static readonly long Frequency = GetFrequency();

	long start_time;
	long end_time;

	public TimerBlock()
	{
		start_time = 0;
		end_time = 0;
		QueryPerformanceCounter(ref start_time);
	}
	public void Dispose()
	{
		QueryPerformanceCounter(ref end_time);
	}

	public double TimePassed { get { return (end_time - start_time) / (double)Frequency; } }
	public long InstructionsPassed { get { return end_time - start_time; } }
	public long StartCounter { get { return start_time; } } 
	public long EndCounter { get { return end_time; } }
}
}

 

 

Hos meg bruker metode 2 hele 0.22453 sekunder på å gjennomføre, mens  metode 1 bruker 0.00003 sekunder.

Lenke til kommentar
using System;
using System.Collections.Generic;

namespace TimeTaker
{
static class Program
{
	static void Main()
	{

		List<double> list;
		int count = 10000000;

		TimerBlock timer;
		using (timer = new TimerBlock())
		{
			list = new List<double>(count);
		}
		Console.WriteLine("Time passed: " + timer.TimePassed.ToString() + " seconds");
		using (timer = new TimerBlock())
		{
			list = new List<double>();
			for (int i = 0; i < count; i++)
			{
				list.Add(0);
			}
		}
		Console.WriteLine("Time passed: " + timer.TimePassed.ToString() + " seconds"); 

	}


}

public class TimerBlock : IDisposable
{
	[System.Runtime.InteropServices.DllImport("Kernel32")]
	static extern bool QueryPerformanceCounter(ref long counter);
	[System.Runtime.InteropServices.DllImport("Kernel32")]
	static extern bool QueryPerformanceFrequency(ref long freq);

	static long GetFrequency()
	{
		long val = 0;
		QueryPerformanceFrequency(ref val);
		return val;
	}

	static readonly long Frequency = GetFrequency();

	long start_time;
	long end_time;

	public TimerBlock()
	{
		start_time = 0;
		end_time = 0;
		QueryPerformanceCounter(ref start_time);
	}
	public void Dispose()
	{
		QueryPerformanceCounter(ref end_time);
	}

	public double TimePassed { get { return (end_time - start_time) / (double)Frequency; } }
	public long InstructionsPassed { get { return end_time - start_time; } }
	public long StartCounter { get { return start_time; } } 
	public long EndCounter { get { return end_time; } }
}
}

 

 

Hos meg bruker metode 2 hele 0.22453 sekunder på å gjennomføre, mens  metode 1 bruker 0.00003 sekunder.

 

 

Lurer på om det var din tur og tulle litt nå :) I den første metoden looper du ikke og legger inn verdier i alle posisjoner. Du instansierer bare listen 0.22 stemmer omtrent med det jeg får. Men får 0.3 i metode 1 når jeg setter capacity samt legger inn elementer. . I tillegg fant jeg System.Diagnostics.Stopwatch klassen. Antar den kan erstatte TimerBlock klassen din? Uansett er det tydeligvis minimal nytte av å bry seg med capacity variabelen.

 

Opprinnelig grunn til å skrive testen var for å skrive en sammenligning med VB 6.0. Her ble det kjørt en preserve metode som utvidet arrayet for hvert element som ble lagt til (dette går eksponensielt tregere for hvert element som ble lagt til. Sikkert fordi alle vrediene ble kopiert/flyttet fordi en laget et nytt array med preserve metoden. Men selv om en forhåndsallokerer arrayet. Tar denne operasjonen 2 sek i VB6.0. Har laget en egen listeklasse i VB6.0 for dynamisk å legge til verdier samt utvide "innerarrayet" med fornuftige verdier. Da tar det 8 sek!. Opprinnelig tok denne operasjonen 15 min! Mens det tar 0.2- 0.3 sek i C#! Utrolig merkelig da jeg trodde VB6.0 skulle være raskere på en slik operasjon fordi det slipper å gå veien om .NET framework mtp. minneallokering. Har du noen ide hva dette kan skyldes?

Lenke til kommentar
Lurer på om det var din tur og tulle litt nå   :) I den første metoden looper du ikke og legger inn verdier i alle posisjoner. Du instansierer bare listen 0.22 stemmer omtrent med det jeg får. Men får 0.3 i metode 1 når jeg setter capacity samt legger inn elementer. . I tillegg fant jeg System.Diagnostics.Stopwatch klassen. Antar den kan erstatte TimerBlock klassen din? Uansett er det tydeligvis minimal nytte av å bry seg med capacity variabelen.

 

Opprinnelig grunn til å skrive testen var for å skrive en sammenligning med VB 6.0. Her ble det kjørt en preserve metode som utvidet arrayet for hvert element som ble lagt til (dette går eksponensielt tregere for hvert element som ble lagt til. Sikkert fordi alle vrediene ble kopiert/flyttet fordi en laget et nytt array med preserve metoden. Men selv om en forhåndsallokerer arrayet. Tar denne operasjonen 2 sek i VB6.0. Har laget en egen listeklasse i VB6.0 for dynamisk å legge til verdier samt utvide "innerarrayet" med fornuftige verdier. Da tar det 8 sek!. Opprinnelig tok denne operasjonen 15 min! Mens det tar 0.2- 0.3 sek i C#! Utrolig merkelig da jeg trodde VB6.0 skulle være raskere på en slik operasjon fordi det slipper å gå veien om .NET framework mtp. minneallokering. Har du noen ide hva dette kan skyldes?

 

 

Hehe ja, jeg la ikke til noen verdier :S

 

Med litt fiks fikk jeg dette:

 

0.099371599121128265 sekunder

 

0.25436910475542979 sekunder

 

 

 

Når det gjelder minneallokering så overrasker det meg litt at det er noen forskjell. Dog kan forskjellen ligge i at VB6 kompilerer utelukkende til 32-bit programkode, mens .NET kompilerer til 64-bit. Men det burde likevel ikke vært så stor forskjell...

 

Det kan dog være tester som VB6 utfører som .NET ikke gjør, men dette er rene spekulasjoner fra min side.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...