R Profiler (Teil 1)
Der Profiler in R ist ein sehr praktisches Tool
, wenn Sie größere Programme entwickeln oder wirklich große Datenanalysen durchführen.
und Sie führen im Grunde genommen R-Code aus,
der viel Zeit oder länger in Anspruch nimmt, als Sie warten möchten.
Und natürlich ist das alles relativ,
je nachdem, woran Sie gerade arbeiten und woran Sie arbeiten.
Vielleicht gibt es noch einige andere Dinge, die Sie tun können, während Sie ein Programm ausführen.
Aber wenn etwas lange dauert, ist der Profiler ein wirklich
praktisches Tool, um genau herauszufinden, warum es so viel Zeit in Anspruch nimmt
und wie, und um Strategien zur Behebung Ihres Problems vorzuschlagen.
Ich werde also ein wenig über die Verwendung des R-Profilers und
unseres und und sprechen, wann Sie ihn möglicherweise verwenden müssen.
Es gibt auch einige andere Tools, über die ich sprechen werde, die
Ihnen helfen, Ihre Programme und Funktionen zu timen
, und so
ist die Verbindung des Profils mit diesen anderen Tools eine wirklich praktische Toolbox,
um herauszufinden, wie Sie Ihre Software optimieren können.
Die erste Frage, die Sie sich stellen möchten
, ist, wissen Sie, läuft Ihr Code tatsächlich langsam?
Und manchmal können Sie dieses Problem lösen
, indem Sie einfach Ihr Programm ausführen und dann etwas anderes tun.
Aber manchmal ist das keine Option und Sie müssen Ihr Programm wirklich schnell ausführen. Die
Profilerstellung ist also eine allgemeine, systematische Methode, um zu untersuchen,
wie viel Zeit in verschiedenen Teilen Ihres Programms aufgewendet wird.
Und es ist besonders nützlich, wenn Sie versuchen
, Ihren Code zu optimieren, Sie wissen schon,
eine Menge Effizienz aus
einem Code herauszuholen, und oft, wenn Sie anfangen, Code zu schreiben
, läuft er gut, Sie wissen schon, wenn Sie
ihn einmal ausführen und vielleicht einen kleinen Teil einer
Funktion oder einen kleinen Teil eines
größeren Programms ausführen, und es sieht toll aus, wenn Sie es ausführen es,
es scheint sehr schnell zu laufen, wenn du es tust.
Aber manchmal werden diese Teile in ein viel größeres Programm eingebettet.
Es kann sein, dass ein größeres
Programm Ihr Stück tausend Mal
oder fünftausend Mal oder sogar zehntausend Mal ausführt.
Und dann
verlangsamt dein kleines Stück, das großartig lief, als du es ausgeführt hast, irgendwie alles
andere, weil es zehntausend Mal ausgeführt wird.
Und jetzt müssen Sie es
viel schneller machen, weil es oft iteriert wird.
Und so ist es, wenn Profiling ins Spiel kommen kann, wenn Sie zum Beispiel einen
Code haben, der hervorragend läuft, aber wenn er dann
in ein größeres Teil eingebettet wird, beginnt es, es, es,
das, die, es, seine Geschwindigkeit wird viel spürbarer.
Wenn es also um die Optimierung Ihres Codes geht,
lautet die allgemeine Regel, dass Sie dies nicht tun sollten.
Und was ich damit meine ist, dass Sie zuerst nicht darüber nachdenken sollten.
Es sollte und das Erste,
worüber Sie nachdenken sollten, ist, wie, wie man
den Code zum Laufen bringt, wie man ihn
lesbar macht, wie man sicherstellt, dass andere Leute verstehen können,
was man tut.
Und weil, und einer der Gründe ist, dass es oft schwer
zu verstehen ist, wo genau Ihr Programm die ganze Zeit verbringt.
Und damit Sie Ihr Programm beschleunigen können,
müssen Sie wissen können, wo es seine Zeit verbringt.
Das geht also nicht ohne jegliche,
ich würde sagen, es ist schwierig, ohne eine formelle Leistungsanalyse oder Profilerstellung.
Die Grundidee ist also, dass Sie Ihren Code immer zuerst entwerfen und
ihn so gestalten sollten, dass er verständlich ist, und dann,
wenn etwas funktioniert, versuchen Sie, ihn zu optimieren.
und dann lautet der berühmte Satz,
wissen Sie, vorzeitige Optimierung ist die Wurzel allen Übels.
Wenn Sie versuchen, zuerst zu optimieren, besteht die Möglichkeit, dass Sie Fehler einführen
, bevor Sie überhaupt welche haben. Sie haben die Möglichkeit, die Dinge überhaupt zum Laufen zu bringen.
Sobald Sie sich
jedoch entschieden haben, Ihren Code zu optimieren, sollten Sie sich, Sie wissen schon, wie ein Wissenschaftler verhalten.
Genau wie in jedem anderen Kontext sollten Sie einige Daten sammeln. In
Ordnung, wenn Sie also ein Gefühl dafür haben, wo
Ihr Programm irgendwie festgefahren ist oder wo es seine
ganze Zeit verbringt, sollten Sie die Daten sammeln, um das herauszufinden, und die Art
und Weise, wie Sie die Daten sammeln, ist die Profilerstellung.
[BLANK_AUDIO]
Also, das erste Tool, über das ich sprechen werde, ist eigentlich nicht
der Profiler, es ist eine sehr einfache Funktion namens system.time in R.
Und was system.time tut, ist, dass es einen beliebigen R-Ausdruck nimmt und diesen Ausdruck auswertet und
Ihnen dann mitteilt, wie viel
Zeit für die Auswertung dieses Ausdrucks benötigt wurde.
Nun könnte dieser Ausdruck sehr einfach sein, wie ein einzelner Funktionsaufruf, oder er
könnte sehr kompliziert sein, wenn er in geschweifte Klammern eingeschlossen werden muss.
Es könnte also tatsächlich ein sehr langer Ausdruck sein, wenn Sie es sein wollten.
Die Grundidee ist also, dass Sie diesen Ausdruck nehmen und er
Ihnen die Zeit in Sekunden gibt, die für die Ausführung des Ausdrucks benötigt wurde.
Wenn während der
Auswertung des Ausdrucks ein Fehler im Code auftritt, erhalten Sie die Zeit, bis der Fehler aufgetreten ist.
Nun, es gibt zwei sehr wichtige Zeitvorstellungen
, wenn Sie EXE sind und Expression auf dem Computer ausführen.
Die erste wird Benutzerzeit genannt. Dies ist die
Zeit, die der CPU
oder den CPUs für die Ausführung dieses Ausdrucks in Rechnung gestellt wird.
Okay, das ist grob gesagt die Art von Zeit, die der Computer erlebt.
Die verstrichene Zeit wird manchmal als Wanduhrzeit bezeichnet
und dies ist die Zeitspanne, die Sie erleben.
Es ist in Ordnung, also die, die, obwohl Sie der Benutzer sind, sind Sie nicht die Benutzerzeit
, Sie erleben die verstrichene Zeit. Und so
können die beiden unterschiedlichen Zeitvorstellungen unterschiedlich wichtig sein, je nachdem, was Ihnen wichtig ist.
Normalerweise liegen also die Benutzerzeit und die verstrichene Zeit relativ
nahe beieinander, weil die Zeit, die der Computer damit verbringt
, Ihr Fu, Ihre Funktion oder Ihren Ausdruck, auszuführen, ungefähr
der Zeit entspricht, die Sie damit verbringen, darauf zu warten, richtig.
Diese sind für Standardtypen von Rechenaufgaben vorgesehen.
Es gibt jedoch Zeiten, in denen die verstrichene Zeit
größer als die Benutzerzeit ist, und
manchmal ist die verstrichene Zeit kleiner als die Benutzerzeit.
In der ca kann die verstrichene Zeit also größer sein als die Benutzerzeit, was bedeutet,
dass Sie mehr Zeit damit verbringen, herumzuwarten
, als der Computer tatsächlich aufgewendet hat, wissen Sie, sich mit
Ihrem Code und dem Grund, ob, und die Idee, dass das c, der Computer möglicherweise viel
Zeit damit verbringt, herumzulesen, ob andere Dinge passieren,
Dinge, die vielleicht außerhalb des Programms selbst liegen.
Und so verbringt die CPU nicht wirklich viel Zeit damit, an Ihrem Code zu arbeiten,
sondern möglicherweise viel Zeit mit
anderen Dingen, die im Hintergrund vor sich gehen.
Wenn die verstrichene Zeit kleiner als die Benutzerzeit ist, tritt dies am häufigsten auf, wenn
Ihr Computer über mehrere Kerne oder Prozessoren verfügt und
leistungsfähig ist und diese ausnutzen kann.
Also das, so wie die meisten Computer heutzutage, haben mindestens
zwei oder vier Kerne oder Mehrkernmaschinen, und das ist
eine sehr häufige Situation.
Es ist jedoch nicht immer so, dass die Berechnung, das Programm, das
Sie ausführen, dazu dient, die Verwendung mehrerer Kerne auszunutzen.
Insbesondere R, das Basisprogramm von R, verwendet noch nicht mehrere Kerne.
Es enthält jedoch häufig Links zu Bibliotheken, die mehrere Kerne verwenden, und
die gebräuchlichste ist die Bibliothek vom Typ lineare Algebra.
Wenn Sie also so etwas wie Regression
oder viele, viele dieser
Vorhersageroutinen oder Matrixberechnungen durchführen, beinhalten diese alle Bibliotheken für lineare Algebra.
Und viele dieser Bibliotheken wurden für die Verwendung mehrerer Kerne optimiert.
Und so sind sie, sie werden
Multithread-BLAS-Bibliotheken oder, für die grundlegenden
Standardbibliotheken der linearen Algebra, Unterroutinenbibliotheken und auf
dem MAC manchmal VecLib oder Accelerate genannt.
Es gibt allgemeinere Bibliotheken wie ATLAS
für AMD-Maschinen, es gibt ACML oder ACML und
für INTEL-Maschinen gibt es MKL.
Es gibt auch Parallelverarbeitungsbibliotheken, zum
Beispiel das Parallel-Paket, das nicht
verwendet, das mehrere Kerne verwenden kann, aber auch mehrere Computer verwenden kann.
Das wird also potenziell
zu einem Programm führen, das mehr
Benutzerzeit in Anspruch nimmt als verstrichene Zeit, und ich werde ein Beispiel dafür geben, wie das funktionieren wird.
Ein Beispiel, wenn die verstrichene Zeit größer ist als
die Benutzerzeit, ist, wenn Sie etwas aus dem Internet lesen.
Also hier verwende ich nur die Funktion „Zeilen lesen“, um eine Webseite
aus, aus, von einem Remote-Server zu lesen.
Und Sie können sehen, dass die verstrichene Zeit ungefähr
0,4 Sekunden beträgt, aber die Benutzerzeit ungefähr 0,004 Sekunden beträgt.
Die CPU verbringt also nicht viel Zeit damit,
diesen Code auszuführen, weil der Großteil der Zeit einfach damit verbracht wird, darauf
zu warten, dass das Netzwerk es tut, oder darauf zu warten, dass die Daten
irgendwie über das Netzwerk übertragen werden und zu Ihrem Computer zurückkehren. Es
ist also nicht wirklich Teil Ihres Programms, darauf zu warten, dass das Netzwerk die Daten verarbeitet, die kommen, dorthin gehen und zurückkommen, sondern
Teil einer anderen Sache, die der Computer tut,
und daher ist die Zeit, in der Ihr Programm ausgeführt
wird, in dem Fall nur die ReadLines-Funktion, relativ gering.
Und im zweiten Beispiel, hier ist die verstrichene Zeit geringer als die
Benutzerzeit. Ich habe eine einfache Funktion erstellt,
die eine Matrix vom Typ Hilbert erzeugt.
Und ich berechne die Singulärwertzerlegung
dieser Ma-Matrix mit der SVD.
Die svd-Funktion verwendet also das
Accelerate-fr-Framework auf dem Mac
und, eine Multithread-Bibliothek für lineare Algebra.
Und so kann es die
beiden verschiedenen Kerne dieses Computers nutzen, den ich verwende.
Und so können Sie sehen, dass die Benutzerzeit ungefähr das Doppelte der verstrichenen Zeit war.
Die verstrichene Zeit betrug also etwa 0,7 Sekunden und die Benutzerzeit etwa 1,6 Sekunden.
Und das Pa, und der Grund dafür ist, dass
die zugrunde liegende lineare Algebra-Bibliothek
die Berechnung auf die beiden Kerne aufgeteilt hat.
Und so kann man sich das vorstellen, aber im Grunde
wurde die verstrichene Zeit mit zwei multipliziert, weil sie auf zwei verschiedenen CPUs ausgeführt wurde.
Die Zeit, die der Benutzer und die CPU mit der Arbeit an Ihrem Programm verbracht haben,
war also tatsächlich mehr als die Zeit, die Sie damit verbracht haben, darauf zu warten, dass es
zurückkommt.
Sie können längere Ausdrücke zeitlich
festlegen, indem Sie einfach alles in geschweifte Klammern einwickeln.
Also hier habe ich eine Vier-Schleife
, die nur einige zufällige normale Variablen generiert.
Und Sie können das Ganze in geschweifte Klammern wickeln und die Systemzeit darum herum aufrufen.
Und Sie können sehen, dass dies hier
ein sehr einfacher Ausdruck ist, es ist kein Multithread-Vorgang,
es gibt keine Netzwerkaktivität, sodass die
Zeit des Benutzers und die verstrichene Zeit im Grunde identisch sind.
Das ist also manchmal eine sehr praktische Funktion, wenn Sie nur
ein kleines Stück Code nehmen wollen, um herauszufinden, wie lange es dauert, ihn
auszuführen, und wenn Sie ein Programm vielleicht Ausdruck für
Ausdruck oder Zeile für Zeile durchgehen wollen, um zu sehen, welche Teile viel Zeit in Anspruch nehmen.
Das Problem mit der Systemzeit besteht darin
, dass davon ausgegangen wird, dass Sie wissen, wo Sie suchen müssen.
Geht davon aus, dass Sie wissen, wo das Problem liegt
, und dass Sie die Systemzeit für einen bestimmten Ausdruck aufrufen können.
Dies kann also für kleinere Programme nützlich sein, für weniger komplizierte Programme,
bei denen Sie ein sehr gutes Gespür dafür haben, wo die Engpässe liegen.
Aber die Frage ist, weißt du was, wenn du nicht weißt, wo du anfangen sollst.
Was ist, wenn Sie nicht wissen, wo die Probleme liegen könnten und wo Sie anfangen sollen zu suchen?
Also brauchst du einen anderen Funktionator, der dir dabei hilft.
R Profiler (Teil 2)
Das ist also der R Profiler.
Und der R Profiler hat eine Funktion in R, die Rprof heißt.
Und es wird ein Rprof verwendet, um den Profiler in R zu starten.
Man könnte beachten, dass R mit
Profiler-Unterstützung kompiliert werden muss und es daher nicht in allen Fällen gebaut wird.
Aber, und ich würde sagen, in 99,9% der Fälle ist das wahr, das ist
die Wahrheit, also du wirst nur, R wird ohne
Profiler-Unterstützung nur unter sehr speziellen Umständen kompiliert.
Und das würde ich nicht tun, die Chancen stehen gut, dass Ihre Version von R den Profiler verwenden kann.
Die andere nützliche Funktion ist die zusammenfassende
Rprof-Funktion, die die Ausgabe des Profilers nimmt und
sie auf lesbare Weise zusammenfasst, da die
Rohausgabe des Profilers im Allgemeinen nicht sehr brauchbar ist.
Deshalb ist die zusammenfassende Rprof-Funktion sehr wichtig.
Es ist wichtig zu wissen, dass Sie die
Systemzeitfunktion und die R-Profiler-Funktion nicht zusammen verwenden sollten.
sie, diese sind nicht wirklich dafür konzipiert, zusammen gearbeitet zu werden, um zusammen verwendet zu werden.
Du solltest also immer das eine oder das andere verwenden und nicht beide.
Die Rprof-Funktion verfolgt also im Grunde genommen den
Funktionsaufruf-Stack in regelmäßig abgetasteten Intervallen, oder?
Und so geht es im Grunde, während Ihre Funktion läuft, es
geht irgendwie, es fragt den Funktionsaufruf-Stack ab, also wie
viele Funktionen Sie, Funktionen, die andere Funktionen aufrufen, die andere Funktionen aufrufen.
Und es druckt es einfach aus.
Im Grunde ist das alles, was es tut, den Funktionsaufruf-Stack in sehr
kurzen Intervallen, also alle 0,02 Sekunden,
und es druckt den Funktionsaufruf-Stack aus.
Als Erstes werden Sie also feststellen, dass, wenn die
Ausführung Ihrer Funktion weniger als 0,02 Sekunden dauert, dieser R, der Profiler nutzlos ist.
Und im Allgemeinen, weil es niemals den Funktionsaufruf-Stack abtasten wird.
Und im Allgemeinen ist der Profiler nicht nützlich, wenn Ihr Programm sehr schnell ausgeführt wird.
Nun, und natürlich, wenn Ihr Programm sehr schnell läuft,
würden Sie wahrscheinlich nicht daran denken, den Profiler überhaupt auszuführen.
Es ist also normalerweise kein Problem.
Aber Sie müssen den Profiler wirklich in Situationen verwenden, in denen
die Bestellung viel länger dauert, zumindest in der Größenordnung von Sekunden.
Hier ist also nur ein kurzes Beispiel für die Rohausgabe,
die vom Profiler stammt.
Nun, Sie werden diese Ausgabe im Allgemeinen niemals verwenden, aber
ich dachte, es könnte interessant sein, sich anzusehen, was vor sich geht.
Sie können also sehen, dass ich, Sie, ich nur die
lm-Funktion rufe, was quasi ein univariates Ergebnis und ein univariater Prädiktor ist.
Und was hier passiert, wie Sie sehen können,
ist jede Zeile dieser Ausgabe der Funktionsaufruf-Stack.
Du kannst also ganz rechts sehen, ist quasi oben.
und, und ganz
links ist sozusagen ganz unten.
Und dann, also ganz rechts, kannst du sehen, dass
lm hieß, und lm hieß eval und eval hieß eval.
Also gehe ich hier von rechts nach links.
Und eval rief model frame auf, was model frame
default aufgerufen hat, was wiederum eval und eval in der Liste aufgerufen hat.
All diese Funktionen rufen sich also gegenseitig auf.
Sie können also sehen, dass die Funktionsrückrufe in die Tiefe gehen.
Wenn Sie in der Auswertung weiter gehen, können Sie feststellen
, dass sich der Funktionsaufruf ändert.
Ganz unten können Sie also sehen, dass lm lm.fit aufgerufen hat.
Und wenn Sie mit der LM-Funktion nicht vertraut sind, lm.fit ist wirklich
das Arbeitspferd dieser Funktion, sie führt alle Arten von Berechnungen durch.
Sie würden also nicht vermuten, dass es
eine angemessene Zeit in der lm.fit-Funktion verbringen würde.
Diese Art von Rohausgabe ist also nicht
besonders einfach zu lesen, daher verwenden wir die
Funktion SumaryRProf, um den Rprof oder die Ausgabe tabellarisch darzustellen
und zu berechnen, wie viel für welche Funktion ausgegeben wird.
Die Idee ist also, dass, sobald Sie den Funktionsaufruf-Stack sehen, Sie wissen
, dass jede Zeile des Cons, der
Funktionsaufruf-Stapel durch 0,02 Sekunden getrennt ist.
Greifen Sie auf die Frequenz zu, die abgetastet wird.
Vorausgesetzt, Sie können berechnen, wie viele Sekunden
in jeder der Funktionen verbracht werden, denn wenn sie im
Funktionsaufruf-Stack erscheinen, verbringen Sie tatsächlich, dann müssen Sie einige Zeit damit verbringen.
Es gibt also zwei Methoden, um die
Daten zu normalisieren, die Sie mit dem R Profiler erhalten.
Eine wird von.total aufgerufen, wodurch die in
jeder Funktion verbrachte Zeit durch die Gesamtlaufzeit geteilt wird.
Und by.self, das dasselbe tut, aber zunächst die
Zeit abzieht, die für Funktionen oben im Aufruf-Stack aufgewendet wurde. Es ist
also wichtig, sich darüber im Klaren zu sein, dass die beiden
unterschiedlichen Konzepte hier sozusagen von, by.total und by self sind.
Die Grundidee ist, dass mit insgesamt, ich meine, die Normalisierung anhand der
Gesamtzeit, die in einer Funktion verbracht wurde, Ihnen im Grunde gibt,
wie viel Zeit aufgewendet wurde, also wie viele, wie oft diese Funktion im Grunde, wie
oft diese Funktion in den Aufrufen auftauchte, in der Art von Ausdruck hier.
Und so werden zum Beispiel 100% Ihrer Zeit in der
Funktion der obersten Ebene verbracht, richtig, also die Funktion, die Sie aufrufen, nehmen wir an, es ist lm, Sie verbringen
100% Ihrer Zeit in dieser Funktion, weil sie auf der obersten Ebene war.
Also, aber die Realität ist, dass
die Funktionen der obersten Ebene oft nichts
damit anfangen, was irgendwie wichtig ist, sie
rufen nur Hilfsfunktionen auf, die die eigentliche Arbeit erledigen, oder?
Wenn Ihre Funktion also
viel Zeit damit verbringt, etwas zu tun, ist es wahrscheinlich, dass sie
viel Zeit in diesen Hilfsfunktionen verbringt, die nur von dieser
Top-Funktion aufgerufen werden, um die ganze Arbeit zu erledigen.
Und so oft ist es nicht sehr interessant zu wissen, wie viel Zeit für
diese Top-Level-Funktionen aufgewendet wird, weil dort nicht
die, wo die wirkliche Arbeit stattfindet, wo die eigentliche Arbeit stattfindet. In
Ordnung, Sie möchten also wirklich wissen, wie viel Zeit in der
Funktion der obersten Ebene verbracht wird, aber ziehen Sie alle
unteren Funktionen ab, die sie aufruft, oder?
Es stellt sich also heraus, dass es viel Zeit in der
Funktion der obersten Ebene verbringt, aber selbst nachdem Sie alle
Funktionen der unteren Ebene abgezogen haben, hat das etwas Interessantes.
Aber meistens werden Sie feststellen, dass, wenn Sie alle
Funktionen der unteren Ebene abziehen, die aufgerufen werden, sehr
wenig Zeit in der Funktion der obersten Ebene verbringt.
Und weil die ganze Arbeit und alle Berechnungen
auf der unteren Ebene der Funktion erledigt werden,
sollten Sie sich darauf konzentrieren.
Das buy.self-Format ist also meiner Meinung nach das
interessanteste Format, weil es Ihnen sagt, wie viel Zeit
in einer bestimmten Funktion verbracht wird, aber nachdem alle
anderen, die gesamte Zeit, die in Funktionen auf niedrigerer Ebene verbracht wurde, abgezogen werden, die gesamte Zeit, die in Funktionen auf niedrigerer Ebene verbracht wurde, die sie aufruft.
Ich denke, es gibt Ihnen ein genaueres
Bild davon, Sie wissen schon, welche Funktionen wirklich, wirklich
die meiste Zeit in Anspruch nehmen und welche Funktionen
Sie möglicherweise später optimieren möchten.
Hier ist also ein Beispiel für einige Ausgaben im Format by.total und Sie können ganz
oben sehr deutlich sehen, dass 100% der Zeit in der Funktion lm verbracht werden.
Die Gesamtzeit für diesen Lauf betrug also 7,41 Sekunden.
Und das alles wurde in lm ausgegeben.
Natürlich, weil lm die oberste Funktion war.
Aber das sieht man und so
sieht man, dass der Zweitplatzierte die Funktion lm.fit war.
Ich habe erwähnt, dass in lm.fit ein Großteil der Berechnungen stattfindet.
Und das waren dreieinhalb Sekunden,
also etwa die Hälfte der Zeit in dieser Funktion.
Jetzt sehen Sie auch, dass eine Reihe von
Funktionen hier model.frame, model.frame.default, eval,
all diese Funktionen nicht wirklich mit
Berechnungen verbunden sind, aber
innerhalb dieser Funktionen wird eine angemessene Menge an Zeit aufgewendet, das ist also interessant.
Nun, ich denke, eine nützlichere Ausgabe ist die by.self-Ausgabe, die quasi
alle Funktionsaufrufe auf niedrigerer Ebene
von so abzieht und berechnet, wie viel
Zeit in a verbracht wurde, sie wird quasi wirklich in einer bestimmten Funktion verbracht.
Und hier können Sie sehen, dass lm.fit der
klare Gewinner ist, denn dort findet wirklich die gesamte Berechnung statt.
Insbesondere ruft lm.fit eine Routine mit vier Trends auf, um eine Matrix zu invertieren.
Und das ist normalerweise der Punkt, an dem bei den meisten groß angelegten Regressionsproblemen
die gesamte Berechnung stattfindet. Die nächste Funktion, die
offenbar oder in 11% der Fälle viel Zeit in Anspruch nimmt,
ist die Funktion as.list für die Methode as.list.data.frame.
Es ist nicht sofort klar, warum so viel Zeit für
diese Funktion aufgewendet wird,
aber es ist vielleicht etwas, das Sie untersuchen möchten.
Weil es vielleicht etwas ist, das für die Art der Kernberechnung nicht sehr wichtig ist.
für, und so kannst du hier die Liste durchgehen
und sehen, wie viel Zeit für verschiedene Funktionen aufgewendet wird.
Und dann werden Sie sehen, dass sich viele dieser Funktionen nicht direkt
auf Berechnungen oder Kernberechnungen
beziehen, sondern eher auf Daten, Formatierung der Daten und dergleichen.
Der letzte Teil der SummaryRProf-Ausgabe ist
nur das Abtastintervall, sodass Sie sehen können,
wie, in welchem Zeitintervall das Sampling
für den Ausdruck des Funktionsaufruf-Stacks stattgefunden hat.
Sie können also sehen, es sind 0,02 Sekunden.
Und die Sampling-Zeit, also nur die
Gesamtzeit, die für die Ausführung des Ausdrucks benötigt wurde.
Das ist die gleiche Art von, das ist also die, glaube ich, äquivalent zur Art der
verstrichenen Zeit in der Funktion system.time.
Das ist also ein kurzer Überblick über den R-Profiler in R,
es ist ein sehr praktisches Tool für Leistungsanalysen, R-Code, um
Ihnen nützliches Feedback zu geben, und ich finde, dass er oft Funktionen hervorhebt,
von denen Sie vielleicht nicht vermutet haben, dass sie Zeitfresser oder Engpässe sind.
Und weil sie nicht wirklich das Herzstück der
Art von Berechnung sind, an der Sie gerade arbeiten.
Der Profiler kann also
meiner Meinung nach sehr nützlich sein, um solche Situationen hervorzuheben
und oft Dinge zu finden, die man irgendwie unerwartet findet.
Die Zusammenfassungsfunktion Rprof fasst die Ausgabe von Rprof zusammen und
gibt Ihnen den prozentualen Zeitaufwand für die einzelnen Funktionen an.
Und ich denke, die by.self-Art der [UNKNOWN] -Normalisierung ist am
nützlichsten, um Engpässe in Ihrem Code hervorzuheben.
Eine der Auswirkungen der Verwendung des
Profilers ist, dass es nützlich ist, Ihren Code in Funktionen zu unterteilen.
Anstatt also eine riesige Funktion
zu haben, ist es nützlich, Ihren Code in logische Teile verschiedener Funktionen zu unterteilen.
Der Profiler kann
Ihnen anhand dieser Informationen mitteilen, wo die Zeit verbracht wird.
Denken Sie also daran, dass der Profiler den Funktionsaufruf-Stack druckt und ausdruckt.
Und wenn Sie Ihren Code in Mul, mehrere kleine Funktionen, aufteilen,
dienen die Funktionsnamen, die Sie angeben, quasi als kleine Identifikatoren.
Im Funktionsaufruf-Stack erfahren Sie
, wo der Code die meiste Zeit verbringt.
Das ist also eine weitere kleine
Strategie, die nützlich sein kann, wenn Sie Ihren R-Code profilieren.
Das Letzte, was es wert ist, zu lernen, ist, dass, wenn Ihr R-Code oder irgendein anderer R-Code
C- oder Fortran-Code aufruft, dieser C- und Fortran-Code kann, wie eine Blackbox ist.
Es ist nicht profiliert.
Du, du wirst keine Informationen über diesen Code sehen.
Sie werden nur wissen, dass
dort einige Zeit verbracht wird, aber Sie werden keine Details darüber wissen.
Insgesamt denke ich, dass der Profiler sehr nützlich ist.
Ich ermutige Sie,
es zu verwenden, anstatt nur zu erraten, Sie wissen schon, wo Sie Ihren Code optimieren müssen, und
der Profiler kann einfach verwendet werden, um
Daten darüber zu sammeln, wo Zeit verbracht wird.