Speicherverbrauch Rekursion
-
Hallo Leute,
ich mach gerade bisschen Memoryprofiler mit VS2012:)
Und da is mir aufgefallen, dass folgende Rekursion rel. viel speicher frist:public IEnumerable<object> GetFlatChildrenOfType(Type type) { return _children .Where(it => type.IsAssignableFrom(it.GetType())) .Cast<object>() .Concat(_children .SelectMany(it => it.GetFlatChildrenOfType(type))); }
Jetzt mal allg. gefragt, wie könnte ich diese LINQ anweisung speichersparender machen? geht das überhaupt
Grüße
-
Rekursives
SelectMany()
sollte man immer vermeiden, das hat miserable Speicher- und Performancecharakteristik. Vgl. die Erörterung in [1] (da gehts um rekursive Iteratoren, aber das Problem ist dasselbe, weilSelectMany()
mit Iteratoren implementiert ist).Du kannst dir eine Hilfsfunktion wie folgt bauen:
public static class EnumerableHelper { public static IEnumerable<T> FlattenRecursive<T>(T item, Func<T, IEnumerable<T>> subitemSelector) { return Flatten(new[] { item }, subitemSelector); } public static IEnumerable<T> FlattenRecursive<T>(IEnumerable<T> items, Func<T, IEnumerable<T>> subitemSelector) { // TODO: implement } }
Das wäre eine prima Übung für eine Einstiegsvorlesung in Algorithmen und Datenstrukturen
Bonuspunkte gibt es, wenn man die gewünschte Rekursionsabfolge wählen kann:
public enum TreeRecursionMode { DepthFirst, BreadthFirst }
Am leichtesten ist die Implementation übrigens in F#, weil du da
yield!
benutzen kannst, was dir genau diese Arbeit abnimmt. In C# mußt du von Hand einen Stack von Enumeratoren verwalten.Wenn du über
FlattenRecursive()
verfügst, kannst du deine Funktion so implementieren:public IEnumerable<object> GetFlatChildrenOfType(Type type) { return EnumerableHelper.FlattenRecursive(this, obj => obj._children.Where(child => type.IsAssignableFrom(child.GetType())); }
Wie du übrigens siehst, ist das
Cast<object>()
ist überflüssig, weilIEnumerable<T>
kovariant inT
ist. Überhaupt wird deine Funktion viel schöner, wenn du sie generisch machst:public IEnumerable<T> GetFlatChildrenOfType<T>() { return EnumerableHelper.FlattenRecursive(this, obj => obj._children.OfType<T>()); }
-
Danke für deine erleuterungen,
die Funktion würde ich gerne generisch machen, aber die schnittstelle sieht leider die variatne mit dem Typ argument vor!
In C# kanst du doch auch "yield return" machen!?
Dannn profile ich mal deine implementation:)
-
NullBockException schrieb:
In C# kanst du doch auch "yield return" machen!?
Ja. Und?
NullBockException schrieb:
Dannn profile ich mal deine implementation:)
Meine Implementation kennst du doch gar nicht.
-
Meine Implementation kennst du doch gar nicht.
Deinen Helper!
Ja. Und?
weil du von F# geredet hast..
-
NullBockException schrieb:
Meine Implementation kennst du doch gar nicht.
Deinen Helper!
Dir ist nicht aufgefallen, daß da "TODO: implement" vermerkt ist?
Die Funktion ist nicht ganz trivial, aber wenn du ein bißchen nachdenkst, kommst du bestimmt selbst drauf, wie man die baut. Den entscheidenden Hinweis (Enumerator-Stack) habe ich dir schon gegeben.
NullBockException schrieb:
Ja. Und?
weil du von F# geredet hast..
Achso.
yield return
in C# entsprichtyield
in F#, aberyield!
ist ein bißchen anders, das entspricht dem hypothetischenyield foreach
[1], das es in C# leider noch nicht gibt.[1] http://blogs.msdn.com/b/wesdyer/archive/2007/03/23/all-about-iterators.aspx
-
Dir ist nicht aufgefallen, daß da "TODO: implement" vermerkt ist?
Die Funktion ist nicht ganz trivial, aber wenn du ein bißchen nachdenkst, kommst du bestimmt selbst drauf, wie man die baut. Den entscheidenden Hinweis (Enumerator-Stack) habe ich dir schon gegeben.
Dein Pattern .. ja hab ich bemerkt:)
Bist du Mathematiker??
Im dichten Nebel verliert ein Ballonfahrer die Orientierung. Er lässt seinen Ballon langsam ab, bis er am Boden einen Menschen sieht, und ruft herab: "Wo bin ich hier?" Daraufhin grübelt der Passant eine Weile und antwortet: "Im Ballon!"
Er überlegt lange.
Seine Antwort ist absolut korrekt.
Seine Aussage ist zu nichts zu gebrauchen.:p kleiner scherz
-
Selber Schuld wenn du C# verwendest (auch ein kleiner Scherz).
-
ich denke das problem hat nix mit der sprache zu tun^^