Jagh ar egentligen tre frågor då jag funderar lite på vad som är snabbast när det gäller kollections/array och liknande. Är specifika arrays snabbare än arrayer av typen object? Skulle inte tro att det är någon prestandaskillnad att bry sig om mellan typade och generiska arrayer. Enligt Microsoft så skall generics ge bättre prestanda eftersom boxing tar CPU tid, jag gjorde ett väldigt enkelt test och körde med en Generic class och en Object class över 10 000 iterationer vardera, och det gav ju inte någon jättskillnad mellan de båda. Hur gjorde du ditt test? Skillnaden blir ju givetvis inte så stor om man loopar i Object-collectionen (som t ex innehåller int-värden) med en variabel av typen object och sedan inte använder denna i t ex beräkningar : Läste lite fel, jag såg att detta gällde generic collections och inte generiska typer... Ditt test är fullständigt meningslöst. Nej Martin, givetvis tar Console.Writeline det mesta av tiden här. Men rent statistiskt bör inte skillnaden mellan att köra console.writeline i generic loopen skilja sig mycket mot att göra det i object loopen. Den här koden illustrerar skillnaden mellan att använda Generic collections vs object collections : Kompletterar härmed ovanstående test med ett DirectCast-exempel också eftersom detta skall vara snabbare än CType(). Jag la alltså till följande kod i exemplet ovan : Nu är jag ingen .Net expert men är inte Det var väl precis det vi skulle jämföra? Generiska collections mot de gamla vanliga object-collections? Ok, tack för infon. Per, Jag är lite osäker på vad det är du testar. Snarare <b>Generiska collections är snabbare object-collections. Dels för att du slipper "typkastning"(type cast*) vid hämtning av värden. T.ex. Iterationer. Snabbast?
Är specifika arrays snabbare än arrayer av typen object?
Hur snabba är Collections i .NET i jämförelse?
Kan man snabba upp hanteringen av tex Collections?
Jag använder gärna specifika Arrayer då jag har fått för mig att de är snabbare. Jag har försökt att kika på nätet efter litteratur som behandlar detta men mina google färdigheter är nog sämre än min programering :P
Tacksam för svar....Sv: Snabbast?
väldigt marginellt om innehållet i dina arrayer är ref typer.
har du value objekt i arrayerna så blir det lite mer skillnad , men rädslan för boxing är extremt överdriven, folk har läst på forum att boxing är det värsta som finns utan att varken testa det eller sätta det i perspektiv till vad man vill utföra.
Hur snabba är Collections i .NET i jämförelse?
det beror på vad du har för collection
tex en länkad lista är inte arraybaserad och kan växa obegränsat utan att reallokera en stor fet array.
andra listor som tex arraylist,list T etc är arraybaserade och är egentligen bara en wrapper över arrayer
//RogerSv: Snabbast?
Det kommer att ge större utdelning att optimera andra delar av systemet som filaccess och databasanrop.
Koncentrera dig på att göra koden lätt att förstå och underhålla i första hand.
Det du kan tänka på är hur dina arrayer skall användas. Skall du ofta söka i den bör du välja någon typ som du kan göra binärsökning i. Skall du ta bort och lägga till element lite varstans väljer du en typ som är anpassad för det.Sv:Snabbast?
10 000 iterationer, tid i ms:
Object: 3013, 3006, 2946, 2933, 2942
Generics: 2934, 2932, 2934, 2920, 2937
Det är ju som Martin säger att du förmodligen inte kommer att märka någon skillnad alls, utan fokusera på att optimera mer kritisk kod.
Ett annat argument till att använda generics är då att du kan få kompilatorn att säga ifrån redan när du komilerar din kod. Om du exempelvis skall casta en string till en object, och sedan från denna object till en int så upptäcks detta inte av kompilatorn, men det smäller i runtime.
Mvh DavidSv: Snabbast?
foreach o as object in myObjectCollection
...
Detta är ju inte direkt ett realistiskt exempel, eftersom man antaligen i ett verkligt exempel skall använda värdet också. Så om myObjectCollection innehåller integervärden så bör man ju testa med följande loop :
foreach o as object in myObjectCollection
{
int i=(int)o;
... // Använd i här
}
Det kanske ändå inte blir så stor skillnad iofs, men det kan vara intressant att veta om du verkligen typkonverterade värdet i loopen också, eller om du körde med tomma loopar.
Sv:Snabbast?
Kanske inte ett tvättäkta benchmarktest, men här är koden Per:
static void Main(string[] args)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
int duration = 100000;
sw.Start();
for (int i = 0; i <= duration; i++)
{
Obj o = new Obj("ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ", "1000000");
string a = (string)o.t;
string b = (string)o.u;
Console.WriteLine(a + " " + b);
}
sw.Stop();
long objDuration = sw.ElapsedMilliseconds;
sw.Reset();
sw.Start();
for (int i = 0; i <= duration; i++)
{
Gen<String, String> g = new Gen<String, String>("ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ", "1000000");
Console.WriteLine(g.t + " " + g.u);
}
sw.Stop();
long genDuration = sw.ElapsedMilliseconds;
Console.WriteLine("Object: " + objDuration.ToString());
Console.WriteLine("Generics: " + genDuration.ToString());
}
class Obj
{
public Object t;
public Object u;
public Obj(Object _t, Object _u)
{
t = _t;
u = _u;
}
}
class Gen<T, U>
{
public T t;
public U u;
public Gen(T _t, U _u)
{
t = _t;
u = _u;
}
}
Sv: Snabbast?
Antagligen ligger den allra största delen av tiden i "Console.Writeline".
Genomsnittet av dina mätningar är 2968 resp 2931ms. Det skulle kunna vara så att Console.Writeline tar 2930ms vilket innebär att Generics är 38 ggr snabbare än object,
(vilket det naturligtvis inte är men det finns inget i ditt test som säger att det inte är det)Sv:Snabbast?
Det jag ville få fram var att det inte är så stor skillnad mellan generics och object.
Du får gärna göra ett exempel som påvisar detta.
Mvh DavidSv: Snabbast?
Dim c1 As New Collections.Generic.SortedList(Of Integer, Integer)
Dim c2 As New Collections.SortedList()
For i As Integer = 1 To 1000000
c1.Add(i, i)
c2.Add(i, i)
Next
Dim clock As New System.Diagnostics.Stopwatch
clock.Start()
For i As Integer = 1 To 1000000
Dim j As Integer = c1(i)
Next i
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
clock.Reset()
clock.Start()
For i As Integer = 1 To 1000000
Dim j As Integer = CType(c2(i), Integer)
Next i
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
Resultatet på min maskin blev efter fem körningar :
<info>
298 1382
354 1310
319 1328
297 1316
345 1336
</info>
De låga värdena är en generisk collection av integers och de höga värdena är för en objectcollection med boxade integers som måste konverteras med ctype innan de används (med option strict on). Skillnaden är en faktor på fyra ungefär, som ni kan se.
Ps. Det är nog inte alla som känner till det men att deklarera en variabel i en loop så som jag gör ovan kostar inget extra. IL:en som genereras blir identiskt om deklarationen ligger utanför, och tiderna blir densamma. Det deklareras alltså INTE en ny variabel för varje varv i loopen. Vilket är bra för mig som helst lägger deklarationerna så nära den plats där den används som möjligt. Förr la jag alltid variabeldeklarationerna överst, men det har jag tröttnat på :-)
Sv:Snabbast?
clock.Reset()
clock.Start()
For i As Integer = 1 To 1000000
j = DirectCast(c2(i), Integer)
Next i
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
Resultatet den här gången :
<info>
306 1406 1327
354 1341 1261
297 1327 1249
321 1354 1314
299 1373 1248
</info>
DirectCast är tydligen bara marginellt snabbare än CType().
Sv:Snabbast?
Dim c1 As New Collections.Generic.SortedList(Of Integer, Integer)
Dim c2 As New Collections.SortedList()
lite som att jämföra äpplen och päron.
Den ena använder value och den andra referens.
Vad ditt test säger är väl att för value-typer är det snabbare med generic men gör det någon skillnad för referenstyper?Sv: Snabbast?
Anledningen till att jag testade med integers (valuetype) var att jag inte trodde att det var någon större skillnad på att unboxa en valuetype, jämfört med att unboxa en referenstype. Det är ju samma operation, "hämta värdet som pekaren pekar på och lägg det i en ny variabel". Jag testade hur som helst detta också :
Dim c1 As New Collections.Generic.SortedList(Of Integer, Item)
Dim c2 As New Collections.SortedList()
For i As Integer = 1 To 1000000
c1.Add(i, New Item(i))
c2.Add(i, New Item(i))
Next
Dim clock As New System.Diagnostics.Stopwatch
clock.Start()
Dim j As Item
For i As Integer = 1 To 1000000
j = c1(i)
Next i
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
clock.Reset()
clock.Start()
For i As Integer = 1 To 1000000
j = CType(c2(i), Item)
Next i
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
clock.Reset()
clock.Start()
For i As Integer = 1 To 1000000
j = DirectCast(c2(i), Item)
Next i
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
En ny klass Item :
Public Class Item
Public Number As Integer
Public Sub New(ByVal Number As Integer)
Me.Number = Number
End Sub
End Class
Resultatet :
<info>
358 1336 1249
350 1296 1254
313 1341 1289
349 1298 1274
312 1317 1240
</info>
Med andra ord, som jag misstänkte, nästan identiskt resultat jämfört med valuetypes.
Sv:Snabbast?
Förstår jag det rätt så ligger alltså skillnaden i sökningen. Antar att det går mycket snabbara att jämföra integers direkt än boxade. Sv:Snabbast?
Vad vill man göra med sin generiska collections eller object-collections?
Ditt test visar att nyckel uppslagning är snabb. Men detta beror helt på nyckeln:
T.ex.:
Sub Main()
Dim key As Item
Dim c1 As New Collections.Generic.SortedList(Of Item, Item)
Dim c2 As New Collections.SortedList()
For i As Integer = 1 To 1000000
key = New Item(i)
c1.Add(key, key)
c2.Add(key, key)
Next
Dim clock As New System.Diagnostics.Stopwatch
clock.Start()
Dim j As Item
For Each key In c1.Keys
j = c1(key)
Next
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
clock.Reset()
clock.Start()
For Each key In c2.Keys
j = CType(c2(key), Item)
Next
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
clock.Reset()
clock.Start()
For Each key In c2.Keys
j = DirectCast(c2(key), Item)
Next
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
End Sub
Om man nu testar:
Public Class Item
Implements IComparable
Public Number As Integer
Public Sub New(ByVal Number As Integer)
Me.Number = Number
End Sub
Public Function CompareTo(ByVal obj As Object) As Integer Implements System.IComparable.CompareTo
Dim Item As Item = DirectCast(obj, Item)
Return Number.CompareTo(Item.Number)
End Function
End Class
</code>
1809
1581
1599
Så är inte så förvånande object collections snabbare. Antagligen för att den Generiska collectionen måste först kasta till object. Eftersom ett flertal kastningar till objekt kommer att göras då den generiska kollektionen skall hämta ett värde.
Om man lägger till:
Public Class Item
Implements IComparable
Implements IComparable(Of Item)
Public Number As Integer
Public Sub New(ByVal Number As Integer)
Me.Number = Number
End Sub
Public Function CompareTo(ByVal obj As Object) As Integer Implements System.IComparable.CompareTo
Dim Item As Item = DirectCast(obj, Item)
Return Number.CompareTo(Item.Number)
End Function
Public Function CompareTo(ByVal Item As Item) As Integer Implements System.IComparable(Of Item).CompareTo
Return Number.CompareTo(Item.Number)
End Function
End Class
894
1588
1577
Testar man iteration över samlingarna:
Dim clock As New System.Diagnostics.Stopwatch
clock.Start()
For Each key In c1.Keys
Next
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
clock.Reset()
clock.Start()
For Each key In c2.Keys
Next
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
clock.Reset()
clock.Start()
For Each key In c1.Values
Next
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
clock.Reset()
clock.Start()
For Each key In c2.Values
Next
clock.Stop()
Console.WriteLine(clock.ElapsedMilliseconds)
23
35
23
35
Min slutsats:
Generiska collections är snabbare object-collections. Dels för att du slipper "typkastning"(type cast*) vid hämtning av värden. T.ex. Iterationer.
Det finns även en intern vinst för t.ex. sorterade listor där typkastning kan undvikas i den interna jämförelsen, vilket ger snabbare kod.
Så jag ser ingen anledning att använda object-collections. Man bör istället använda generiska collections.
Tar man dock detta i jämförelse med vad som är flaskhalsar i applikationer så är skillnaden trivial i jämförelse med vad det kostar att göra ett databas anrop.
Så det är lite som att diskutera hur man släcker ett ljus bäst när huset står och brinner.
Så har vi ju: Många bäckar små.
1. Få ditt program att fungera
2. Gör ditt program "vackert"/underhållbart
3. Om nödvändigt optimera prestandan
Sv: Snabbast?
1. Välj lämpliga datatyper och algoritmer
2. Gör ditt program "vackert"/underhållbart
3. Få ditt program att fungera
4. Identifiera flaskhalsar
5. Optimera prestandan (vilket oftast innebär att börja om på 1 igen)Sv: Snabbast?
Det finns även en intern vinst för t.ex. sorterade listor där typkastning kan undvikas i den interna jämförelsen, vilket ger snabbare kod. Så jag ser ingen anledning att använda object-collections. Man bör istället använda generiska collections. </b>
Det var ju precis vad jag kom fram till också :-)
<b>Ditt test visar att nyckel uppslagning är snabb.</b>
Jag använder inte nyckeln vid upphämtning av värden i mitt testexempel, jag använder foreach och det bör ju rimligen bli en "enkel loop genom datastrukturen" i bakgrunden i st för en massa "nyckelhämtningar".
Hur som helst, generiska collections är bra, använd dom :-)