Moin.
Mich hat mal interessiert, wie sich yield return Performance-mäßig so verhält im Vergleich zum Arbeiten mit einer Liste.
Dabei kamen sehr interessante Resultate zum Vorschein.
Es wurden mehrere Fälle betrachtet:
1.A) Mix aus List / foreach-yield returns ohne Verwendung der zurückgegebenen Ergebnisse.
2.A) reine yield-returns ohne Verwendung der zurückgegebenen Ergebnisse.
1.B) Mix aus List / foreach-yield returns mit Verwendung der zurückgegebenen Ergebnisse.
2.B) reine yield-returns mit Verwendung der zurückgegebenen Ergebnisse.
Die konkreten Zeiten:
1.A = ~3.240.000 yield, ~490.000 List
2.A = ~4.670.000 yield, ~1.470.000 List
1.B = ~4.920.000 yield, ~11.000.000 List
2.B = ~4.830.000 yield, ~12.800.000 List
Anmerkung:
Die Absolutwerte der Zahlen können durch das Verfahren nicht als repräsentativ erachtet werden, die Verhältnisse zwischen yield und List sind allerdings so massiv, dass sie durchaus brauchbar sind um eine quantitative Aussage darüber abzugeben, ob yield oder eine Liste verwendet werden sollte.
Fazit:
Werden die Ergebnisse einer Enumeration sofort benötigt um sie direkt weiter zu verwenden (was eigentlich niemals der Fall ist, da Werte ja immer benötigt werden oder der Call wäre unsinnig), ist yield absolut im Vorteil. Sollten die Werte aber nur ge-fetched werden, so bleibt die Liste unangefochten, da sie keine unnötige Iteration über die einzelnen Elemente erzwingt.
Würde mich freuen, wenn Ihr Eure Erfahrungen oder Wissen darüber teilen könntet, da ich mich vorher zwar mit yield, aber nie mit dessen Performance auseinander gesetzt habe.
Der Code für den Test sah wie folgt aus:
|
C#-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
YieldTest yt = new YieldTest ( );
long t = DateTime.Now.Ticks;
int x = 0;
for ( int i = 0; i < 1000000; i++ )
#if A
yt.GetThem ( );
#else
foreach ( var y in yt.GetThem ( ) )
x += y;
#endif
long t2 = DateTime.Now.Ticks;
x = 0;
for ( int i = 0; i < 1000000; i++ )
#if A
yt.GetThemList ( );
#else
foreach ( var y in yt.GetThemList ( ) )
x += y;
#endif
long t3 = DateTime.Now.Ticks;
|
|
C#-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
private class YieldTest
{
private Random m_Rand = new Random ( );
public IEnumerable<int> GetThem ( )
{
int choice = m_Rand.Next ( 4 );
int rep = m_Rand.Next ( 15 );
if ( choice == 0 )
{
#if CASE1
for ( int i = 0; i < rep; i++ )
{
yield return (i * 15) % 7;
}
#else
foreach ( int x in GetMore ( ) )
yield return x;
#endif
yield return 24;
}
if ( choice == 1 )
{
foreach ( int x in GetMore ( ) )
{
yield return x;
}
yield return 214;
}
if ( choice == 2 )
{
foreach ( int x in GetMore ( ) )
{
yield return x;
}
yield return 34;
}
if ( choice == 3 )
{
foreach ( int x in GetMore ( ) )
{
yield return x;
}
yield return 94;
}
}
public IEnumerable<int> GetThemList ( )
{
int choice = m_Rand.Next ( 4 );
int rep = m_Rand.Next ( 15 );
List<int> l = new List<int> ( );
if ( choice == 0 )
{
#if CASE1
for ( int i = 0; i < rep; i++ )
{
l.Add ( (i * 15) % 7 );
}
#else
l = GetMore ( );
#endif
l.Add ( 24 );
return l;
}
if ( choice == 1 )
{
l = GetMore ( );
l.Add ( 214 );
return l;
}
if ( choice == 2 )
{
l = GetMore ( );
l.Add ( 34 );
return l;
}
if ( choice == 3 )
{
l = GetMore ( );
l.Add ( 94 );
return l;
}
return null;
}
private List<int> GetMore ( )
{
List<int> ret = new List<int> ( );
int rep = 5 + m_Rand.Next ( 3 );
for ( int i = 0; i < rep; i++ )
{
ret.Add ( 3 * i );
}
ret.Add ( 13 );
return ret;
}
}
|