
Sehr oft werden bei der Lösung von Analyse- und Datenaufbereitungsproblemen einmalige Skripte geschrieben, deren Unterstützung und Entwicklung überhaupt nicht bereitgestellt wird. Dieser Ansatz hat ein Existenzrecht, insbesondere in der Studentengemeinschaft. Wenn jedoch mehr als eine Person mit dem Code arbeitet oder der Code länger als einen Arbeitstag gepflegt werden muss, ist die Möglichkeit, die Arbeit in Form eines Dateihaufens zu organisieren, nicht akzeptabel.
Daher werden wir heute über ein so wichtiges Thema sprechen, wie das Erstellen eines Projekts von Grund auf in der Julia-Sprache, wie es gefüllt wird und welche technologischen Tools zur Unterstützung der Entwicklung vorhanden sind.
Projekt
Wie bereits erwähnt, haben einmalige Skripte oder Jupyter-Notizbücher das Recht, auf dem Desktop einer Person zu existieren, insbesondere wenn die Programmiersprache als erweiterter Taschenrechner verwendet wird. Dieser Ansatz ist jedoch für die Entwicklung von Projekten, die jahrelang entwickelt und betrieben werden sollten, völlig ungeeignet. Und natürlich verfügt Julia als Technologieplattform über Tools, die Entwicklern diese Möglichkeit bieten.
Für den Anfang ein paar allgemeine Punkte. Julia hat ein Pkg-Modul für die Paketverwaltung. Jede Julia-Bibliothek ist ein Modul. Wenn das Modul nicht im Julia-Basiskit enthalten ist, wird es als separates Paket ausgegeben. Für jedes Paket gibt es eine Projektdatei Project.toml
, die eine Beschreibung des Projekts und seiner Abhängigkeit von anderen Paketen enthält. Es gibt eine zweite Datei - Manifest.toml
, die im Gegensatz zu Project.toml
automatisch generiert wird und eine Liste aller erforderlichen Abhängigkeiten mit Paketversionsnummern enthält. Das Toml-Dateiformat ist Toms offensichtliche, minimale Sprache .
Regeln für die Paketbenennung
Gemäß der Dokumentation kann der Paketname aus lateinischen Buchstaben und Zahlen bestehen. Und dieser Name sollte so gewählt werden, dass es den meisten Julia-Benutzern und nicht nur Experten in einem engen Themenbereich klar ist.
- Jargon und kontroverse Kontraktionen, die in verschiedenen Bereichen unterschiedlich verwendet werden, sollten vermieden werden.
- Verwenden Sie nicht das Wort Julia im Paketnamen.
- Pakete, die einige Funktionen zusammen mit den darin deklarierten neuen Typen bereitstellen, sollten im Plural benannt werden.
◦ DataFrames bietet einen DataFrame-Typ.
◦ BloomFilters bietet den BloomFilter-Typ.
◦ Gleichzeitig stellt JuliaParser keinen neuen Typ zur Verfügung, und die neue Funktionalität ist die Funktion JuliaParser.parse (). - Transparenz und Verständlichkeit unter Verwendung des vollständigen Namens sollten der Abkürzung vorgezogen werden.
RandomMatrices
weniger mehrdeutig als RndMat
oder RMT
. - Der Name kann den Besonderheiten des Themenbereichs entsprechen. Beispiele:
◦ Julia hat keine eigenen Grafikzeichnungspakete. Stattdessen gibt es Pakete wie Gadfly
, PyPlot
, Winston
usw., von denen jedes seinen eigenen Ansatz und seine eigene Methodik für die Verwendung implementiert.
◦ Gleichzeitig bietet SortingAlgorithms
eine vollständige Schnittstelle für die Verwendung von Sortieralgorithmen. - In Fällen, in denen Pakete ein Wrapper für einige Bibliotheken von Drittanbietern sind, behalten sie den Namen dieser Bibliothek bei. Beispiele:
◦ CPLEX.jl
ist ein Wrapper über die CPLEX
Bibliothek.
◦ MATLAB.jl
bietet eine Schnittstelle zum Aktivieren von MATLAB
von Julia aus.
Gleichzeitig hat der Name des Git-Repositorys normalerweise das Suffix „.jl“.
Paketerstellung
Der einfachste Weg, ein Paket zu erstellen, besteht darin, es mit einem in Julia integrierten Generator zu generieren. Dazu müssen Sie in der Konsole in das Verzeichnis wechseln, in dem das Paket erstellt werden soll, dann julia ausführen und in den Paketverwaltungsmodus versetzen:
julia> ]
Der letzte Schritt besteht darin, den Paketgenerator zu starten, indem Sie den Namen angeben, den wir dem Paket geben möchten.
(v1.2) pkg> generate HelloWorld
Infolgedessen wird im aktuellen Verzeichnis ein neues Verzeichnis angezeigt, das dem Namen des Pakets entspricht, dessen Zusammensetzung mit dem Befehl tree
(falls installiert) angezeigt werden kann:
shell> cd HelloWorld shell> tree . . ├── Project.toml └── src └── HelloWorld.jl 1 directory, 2 files
In diesem Fall sehen wir einen minimalen, aber unzureichenden Satz von Dateien für ein gut gestaltetes Projekt. Weitere Informationen finden Sie unter https://julialang.imtqy.com/Pkg.jl/v1/creating-packages/ .
Eine alternative Möglichkeit zum Erstellen von Paketen ist der Generator PkgTemplates.jl . Im Gegensatz zum integrierten Generator können Sie sofort einen vollständigen Satz von Servicedateien für die Wartung des Pakets generieren. Der einzige Nachteil ist, dass es selbst als Paket installiert werden muss.
Das Verfahren zum Erstellen eines Pakets mit seiner Hilfe ist wie folgt. Wir verbinden ein Paket:
julia> using PkgTemplates
Wir erstellen eine Vorlage, die eine Liste der Autoren, eine Lizenz, Anforderungen für Julia und eine Liste der Plugins für kontinuierliche Integrationssysteme enthält (ein Beispiel aus der Dokumentation für PkgTemplates
):
julia> t = Template(; user="myusername",
Wir bekommen die Vorlage:
Template: → User: myusername → Host: github.com → License: ISC (Chris de Graaf, Invenia Technical Computing Corporation 2018) → Package directory: ~/code → Minimum Julia version: v0.7 → SSH remote: No → Commit Manifest.toml: No → Plugins: • AppVeyor: → Config file: Default → 0 gitignore entries • Codecov: → Config file: None → 3 gitignore entries: "*.jl.cov", "*.jl.*.cov", "*.jl.mem" • Coveralls: → Config file: None → 3 gitignore entries: "*.jl.cov", "*.jl.*.cov", "*.jl.mem" • GitHubPages: → 0 asset files → 2 gitignore entries: "/docs/build/", "/docs/site/" • TravisCI: → Config file: Default → 0 gitignore entries
Mit dieser Vorlage können wir nun Pakete erstellen, indem wir einfach ihren Namen angeben:
julia> generate(t, "MyPkg1")
In einer Minimalversion sieht die Vorlage möglicherweise folgendermaßen aus:
julia> t = Template(; user="rssdev10", authors=["rssdev10"]) Template: → User: rssdev10 → Host: github.com → License: MIT (rssdev10 2019) → Package directory: ~/.julia/dev → Minimum Julia version: v1.0 → SSH remote: No → Add packages to main environment: Yes → Commit Manifest.toml: No → Plugins: None
Wenn wir aus dieser Vorlage ein Paket mit dem Namen MyPkg2 erstellen:
julia> generate(t, "MyPkg2")
Dann können wir das Ergebnis direkt von Julia überprüfen:
julia> run(`git -C $(joinpath(t.dir, "MyPkg2")) ls-files`); .appveyor.yml .gitignore .travis.yml LICENSE Project.toml README.md REQUIRE docs/Manifest.toml docs/Project.toml docs/make.jl docs/src/index.md src/MyPkg2.jl test/runtests.jl
Die folgenden Felder sollten beachtet werden:
user="myusername"
ist der Name für den Eintrag in der Git-Registrierung.- Verzeichnis für die Platzierung des Paketcodes. Wenn nicht angegeben, wird es im Entwicklungsverzeichnis
~/.julia/dev
. Darüber hinaus ist das ~/.julia
gemäß den Regeln von Unix-Dateisystemen ausgeblendet.
Nach dem Erstellen des Projekts wird ein ausreichender Satz von Dateien generiert und ein Git-Repository erstellt. Darüber hinaus werden alle generierten Dateien automatisch zu diesem Repository hinzugefügt.
Typischer Dateispeicherort in einem Projekt
Wir leihen uns ein Bild mit einer typischen Anordnung von Dateien und deren Inhalten von https://en.wikibooks.org/wiki/Introducing_Julia/Modules_and_packages aus , aber wir werden es ein wenig erweitern:
Calculus.jl/
Wir fügen hinzu, dass das deps
Verzeichnis möglicherweise die Dateien enthält, die für die korrekte Zusammenstellung des Pakets erforderlich sind. Beispielsweise ist deps/build.jl
ein Skript, das automatisch ausgeführt wird, wenn das Paket installiert wird. Das Skript kann beliebigen Code für die Datenaufbereitung (Herunterladen eines Datensatzes oder Vorverarbeitung) oder andere für die Arbeit erforderliche Programme enthalten.
Es ist zu beachten, dass ein Projekt nur ein Hauptmodul enthalten kann. Das heißt, im obigen Beispiel - Calculus
. Im selben Beispiel gibt es jedoch ein verschachteltes Derivatmodul, das eine Verbindung über include
. Achten Sie darauf. include
schließt die Datei als Text ein, nicht als Modul, was beim using
oder import
. Die letzten beiden Funktionen umfassen nicht nur das Modul, sondern zwingen Julia, es als separate Entität zu kompilieren. Außerdem wird Julia versuchen, dieses Modul in den Abhängigkeitspaketen zu finden und eine Warnung ausgeben, dass es in Project.toml
fehlt. Wenn unsere Aufgabe darin besteht, hierarchischen Zugriff auf Funktionen zu ermöglichen und diese durch Namespaces abzugrenzen, fügen wir Dateien über include
und aktivieren das Modul durch einen Punkt, der die lokale Zugehörigkeit angibt. Also:
module Calculus include("derivative.jl") import .Derivative ... end
Die derivative
, die aus dem Derivative
exportiert wird, steht uns über Calculus.Derivative.derivative()
Project.toml Projektdatei
Die Projektdatei ist eine Textdatei. Die Hauptabschnitte sind in der Beschreibung https://julialang.imtqy.com/Pkg.jl/v1/toml-files/ angegeben.
Nachdem die Datei generiert wurde, sind bereits alle erforderlichen Felder vorhanden. Möglicherweise müssen Sie jedoch einen Teil der Beschreibung ändern, die Zusammensetzung der Pakete, ihre Versionen und die spezifischen Abhängigkeiten verschiedener Betriebssysteme oder Konfigurationen ändern.
Die Hauptfelder sind:
name = "Example" uuid = "7876af07-990d-54b4-ab0e-23690620f79a" version = "1.2.5"
name
- Der Name des Pakets, das gemäß den Namensregeln ausgewählt wurde. uuid
ist eine einheitliche Kennung, die von einem Paketgenerator oder einem anderen uuid
Generator generiert werden kann. version
- version
Pakets im Format von drei durch Punkte getrennten Dezimalzahlen. Dies entspricht dem Format von Semantic Versioning 2.0.0 . Vor der deklarierten Version 1.0.0 sind Änderungen an der Programmoberfläche möglich. Nach der Veröffentlichung dieser Version muss der Paketinhaber die Kompatibilitätsregeln einhalten. Kompatible Änderungen sollten in der kleinen Zahl (rechts) angezeigt werden. Inkompatible Änderungen müssen mit einer Änderung der hohen Anzahl einhergehen. Natürlich gibt es keine automatische Kontrolle über die Versionsregel, aber die Nichteinhaltung der Regel führt lediglich dazu, dass Benutzer des Pakets die Verwendung massiv einstellen und auf das Paket migrieren, dessen Autoren diese Regel einhalten.
Alle [deps]
Abschnitt [deps]
.
[deps] Example = "7876af07-990d-54b4-ab0e-23690620f79a" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Dieser Abschnitt enthält eine Liste der direkten Abhängigkeiten unseres Pakets. Kaskadierende Abhängigkeiten spiegeln sich in der Datei Manifest.toml
wider, die automatisch im Projektverzeichnis generiert wird. Alle Abhängigkeiten werden durch =
. Und normalerweise ist dieser Teil nicht mit Händen gefüllt. Hierzu werden die Funktionen des Pkg
Pakets bereitgestellt. Und meistens geschieht dies über REPL
und wechselt in den Paketverwaltungsmodus - ]
. Weiter - die Operationen add
, rm
, st
usw., jedoch immer im Kontext des aktuellen Pakets. Wenn nicht, müssen Sie die activate .
ausführen activate .
.
Manifest.toml
kann im git
Versionskontrollsystem gespeichert werden. Mit diesem Ansatz mit zwei Dateien können Sie die Pakete im Abhängigkeitsbaum während des Testens des Softwareprodukts starr fixieren. Danach wird garantiert, dass bei der Bereitstellung unseres Pakets an einem neuen Speicherort dieselben Versionen von Paketen von Drittanbietern dort wiederholt werden. Umgekehrt erhalten Sie in Abwesenheit von Manifest.toml
die Möglichkeit, alle verfügbaren Versionen zu verwenden, die die Grundbedingungen erfüllen.
Im Abschnitt [compat]
können Sie bestimmte Versionen von Paketen angeben, die wir benötigen.
[deps] Example = "7876af07-990d-54b4-ab0e-23690620f79a" [compat] Example = "1.2" julia = "1.1"
Pakete werden durch den Namen identifiziert, der zuvor im Abschnitt [compat]
. Julia zeigt die Version von Julia selbst an.
Bei der Angabe von Versionen gelten die unter https://julialang.imtqy.com/Pkg.jl/dev/compatibility/ aufgeführten Regeln. Die gleichen Regeln sind jedoch in der semantischen Versionierung angegeben .
Es gibt verschiedene Versionsregeln. Zum Beispiel:
[compat] Example = "1.2, 2"
bedeutet, dass jede Version im Bereich [1.2.0, 3.0.0)
geeignet ist, ohne 3.0.0
. Und dies steht im Einklang mit einer einfacheren Regel:
[compat] Example = "1.2"
Darüber hinaus ist die einfache Angabe der Versionsnummer eine abgekürzte Form von "^1.2"
. Ein Beispiel für die Anwendung sieht aus wie:
[compat] PkgA = "^1.2.3" # [1.2.3, 2.0.0) PkgB = "^1.2" # [1.2.0, 2.0.0) PkgC = "^1" # [1.0.0, 2.0.0) PkgD = "^0.2.3" # [0.2.3, 0.3.0) PkgE = "^0.0.3" # [0.0.3, 0.0.4) PkgF = "^0.0" # [0.0.0, 0.1.0) PkgG = "^0" # [0.0.0, 1.0.0)
Wenn wir strengere Einschränkungen festlegen müssen, muss ein Formular mit einer Tilde verwendet werden.
[compat] PkgA = "~1.2.3" # [1.2.3, 1.3.0) PkgB = "~1.2" # [1.2.0, 1.3.0) PkgC = "~1" # [1.0.0, 2.0.0) PkgD = "~0.2.3" # [0.2.3, 0.3.0) PkgE = "~0.0.3" # [0.0.3, 0.0.4) PkgF = "~0.0" # [0.0.0, 0.1.0) PkgG = "~0" # [0.0.0, 1.0.0)
Nun, und natürlich gibt es einen Hinweis auf gleiche Vorzeichen / Ungleichheiten:
[compat] PkgA = ">= 1.2.3" # [1.2.3, ∞) PkgB = "≥ 1.2.3" # [1.2.3, ∞) PkgC = "= 1.2.3" # [1.2.3, 1.2.3] PkgD = "< 1.2.3" # [0.0.0, 1.2.2]
Im Abschnitt [targets]
mehrere Optionen für Abhängigkeiten angegeben werden. In Julia vor Version 1.2 wurden traditionell Abhängigkeiten für die Verwendung des Pakets und für die Ausführung von Tests angegeben. Zu diesem Zweck wurden im Abschnitt [extras]
zusätzliche Pakete angegeben und Zielkonfigurationen mit Paketnamen unter [targets]
aufgelistet.
[extras] Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] test = ["Markdown", "Test"]
Ab Julia 1.2 wird empfohlen, einfach eine separate Projektdatei für die test/Project.toml
hinzuzufügen.
Zusätzliche Abhängigkeiten
Zusätzliche Abhängigkeiten können über die deps/build.jl
Artifacts.toml
wird jedoch in der Julia-Projektstruktur bereitgestellt. Die Pkg.Artifacts
bietet Funktionen zum Automatisieren des Ladens zusätzlicher Abhängigkeiten. Ein Beispiel für eine solche Datei:
# Example Artifacts.toml file [socrates] git-tree-sha1 = "43563e7631a7eafae1f9f8d9d332e3de44ad7239" lazy = true [[socrates.download]] url = "https://github.com/staticfloat/small_bin/raw/master/socrates.tar.gz" sha256 = "e65d2f13f2085f2c279830e863292312a72930fee5ba3c792b14c33ce5c5cc58" [[socrates.download]] url = "https://github.com/staticfloat/small_bin/raw/master/socrates.tar.bz2" sha256 = "13fc17b97be41763b02cbb80e9d048302cec3bd3d446c2ed6e8210bddcd3ac76" [[c_simple]] arch = "x86_64" git-tree-sha1 = "4bdf4556050cb55b67b211d4e78009aaec378cbc" libc = "musl" os = "linux" [[c_simple.download]] sha256 = "411d6befd49942826ea1e59041bddf7dbb72fb871bb03165bf4e164b13ab5130" url = "https://github.com/JuliaBinaryWrappers/c_simple_jll.jl/releases/download/c_simple+v1.2.3+0/c_simple.v1.2.3.x86_64-linux-musl.tar.gz" [[c_simple]] arch = "x86_64" git-tree-sha1 = "51264dbc770cd38aeb15f93536c29dc38c727e4c" os = "macos" [[c_simple.download]] sha256 = "6c17d9e1dc95ba86ec7462637824afe7a25b8509cc51453f0eb86eda03ed4dc3" url = "https://github.com/JuliaBinaryWrappers/c_simple_jll.jl/releases/download/c_simple+v1.2.3+0/c_simple.v1.2.3.x86_64-apple-darwin14.tar.gz" [processed_output] git-tree-sha1 = "1c223e66f1a8e0fae1f9fcb9d3f2e3ce48a82200"
Wir werden nicht näher darauf eingehen, da die weitere Beschreibung vom spezifischen Anwendungsfall abhängt. Die Bibliotheksfunktionen artifact_hash
, download
, create_artifact
, bind_artifact
. Weitere Informationen finden Sie in der Dokumentation https://julialang.imtqy.com/Pkg.jl/dev/artifacts/ .
Implementierung und Debugging des Hauptcodes
Natürlich geben wir das Entwicklungsverzeichnis beim Erstellen des Pakets explizit oder implizit an. Bei Bedarf können wir dies jedoch ändern. Wenn das Paket von PkgTemplates
mit Standardparametern generiert wurde, suchen Sie es im ~/.julia/dev
. Trotz der Tatsache, dass das Verzeichnis ausgeblendet ist, ist der Übergang zu ihm über einen direkten Link im Datei-Navigator möglich. Für MacOS im Finder erfolgt dies beispielsweise durch Drücken von Befehlstaste + Umschalttaste + G. Wenn das Paket in einem anderen Verzeichnis erstellt wurde, öffnen Sie es einfach in einem Texteditor. Der beste Editor für die Arbeit mit Julia-Code ist Atom und alles, was das uber-juno
Plugin unterstützt. In diesem Fall erhalten Sie einen Texteditor mit automatischer Formatierung des Codes, eine REPL-Konsole für die interaktive Codeausführung, die Möglichkeit, nur ausgewählte Codefragmente auszuführen und die Ergebnisse anzuzeigen, einschließlich der Anzeige von Grafiken. Und auch ein schrittweiser Debugger. Obwohl wir zugeben müssen, dass es im Moment ziemlich langsam ist, also der aktuelle Debugging-Modus - zuerst denken wir, dass wir die Debug-Ausgabe überprüfen und setzen wollen, dann führen wir den Test zum Testen aus.
Es wird empfohlen, gängige Entwurfsmuster für dynamische Programmiersprachen zu betrachten . Auch das Buch "Hands-On Design Patterns mit Julia 1.0. Tom Kwong" und Beispielcode dafür . Bei der Implementierung von Programmen sollten Sie die Empfehlungen zum Programmierstil Julia Style Guide berücksichtigen.
Unter den Feinheiten des Debuggens kann das Revise.jl
Paket erwähnt werden. Die Aktivierung kann in der Datei .julia/config/startup.jl
nur für den interaktiven Modus festgelegt werden, in dem REPL über den Atom-Editor ausgeführt werden kann. Mit Revise können Sie den Funktionscode in unserem Paket bearbeiten, ohne die REPL-Sitzung neu zu starten. Bei jeder Ausführung mit / import in unseren Tests werden diese Aktualisierungen aktiviert.
Für eine effektive Entwicklung wird empfohlen, den Hauptcode und die Tests, die ihn testen, parallel zu entwickeln. Auf diese Weise können Sie nur das implementieren, was wirklich benötigt wird, da sonst in den Tests offensichtlich unnötige Funktionen vorhanden sind. Daher müssen sie entfernt werden. Im Wesentlichen bietet Julia nichts Spezifisches in den Prinzipien der Entwicklung. Der Schwerpunkt liegt jedoch auf der Entwicklung durch Unit-Tests, da Julia den Code ziemlich langsam kompiliert und im schrittweisen Debugging-Modus die Leistung stark reduziert wird. Das heißt, es hängt von der Entwicklung der Tests, ihrer Organisation und der Geschwindigkeit ab, mit der das zu entwickelnde Paket debuggt und verifiziert wird.
Tests
Ein typischer Testort ist das Testverzeichnis. Die Datei test/runtests.jl
ist der Ausgangspunkt für alle Tests.
In Bezug auf das oben erwähnte Beispiel ist die typische Form der Datei:
using Calculus
Es wird empfohlen, Dateien spezifischer Tests auf der Grundlage der Gruppierung der getesteten Funktionen zu entwickeln. Beispielsweise können in dem erwähnten Calculus
verschiedene Algorithmen zum Berechnen von Ableitungen, Integralen usw. vorhanden sein. Es ist logisch, sie mit verschiedenen Tests zu testen, die sich in verschiedenen Dateien befinden.
Für Unit-Tests stellt Julia das Test
aus dem Basisbibliotheks-Set zur Verfügung. In diesem Modul wird das Makro @test
definiert, mit dem die Richtigkeit der angegebenen Anweisung überprüft werden soll. Beispiele:
julia> @test true Test Passed julia> @test [1, 2] + [2, 1] == [3, 3] Test Passed julia> @test π ≈ 3.14 atol=0.01 Test Passed
≈
.
, — @test_throws
. — :
julia> @test_throws BoundsError [1, 2, 3][4] Test Passed Thrown: BoundsError
@testset
. . Zum Beispiel:
julia> @testset "trigonometric identities" begin θ = 2/3*π @test sin(-θ) ≈ -sin(θ) @test cos(-θ) ≈ cos(θ) @test sin(2θ) ≈ 2*sin(θ)*cos(θ) @test cos(2θ) ≈ cos(θ)^2 - sin(θ)^2 end; Test Summary: | Pass Total trigonometric identities | 4 4
, @testset
, . . , — .
julia> @testset "Foo Tests" begin @testset "Animals" begin @testset "Felines" begin @test foo("cat") == 9 end @testset "Canines" begin @test foo("dog") == 9 end end @testset "Arrays" begin @test foo(zeros(2)) == 4 @test foo(fill(1.0, 4)) == 15 end end Arrays: Test Failed Expression: foo(fill(1.0, 4)) == 15 Evaluated: 16 == 15 [...] Test Summary: | Pass Fail Total Foo Tests | 3 1 4 Animals | 2 2 Arrays | 1 1 2 ERROR: Some tests did not pass: 3 passed, 1 failed, 0 errored, 0 broken.
@test_broken
, @test_skip
.
. julia
:
--code-coverage={none|user|all}, --code-coverage Count executions of source lines (omitting setting is equivalent to "user") --code-coverage=tracefile.info Append coverage information to the LCOV tracefile (filename supports format tokens). --track-allocation={none|user|all}, --track-allocation Count bytes allocated by each source line (omitting setting is equivalent to "user")
code-coverage
— . ( ), . , . .cov
. .
:
- function vectorize(str::String) 96 tokens = str |> tokenizer |> wordpiece 48 text = ["[CLS]"; tokens; "[SEP]"] 48 token_indices = vocab(text) 48 segment_indices = [fill(1, length(tokens) + 2);] 48 sample = (tok = token_indices, segment = segment_indices) 48 bert_embedding = sample |> bert_model.embed 48 collect(sum(bert_embedding, dims=2)[:]) - end
track-allocation
— . , , , , .mem
.
:
- function vectorize(str::String) 0 tokens = str |> tokenizer |> wordpiece 6766790 text = ["[CLS]"; tokens; "[SEP]"] 0 token_indices = vocab(text) 11392 segment_indices = [fill(1, length(tokens) + 2);] 1536 sample = (tok = token_indices, segment = segment_indices) 0 bert_embedding = sample |> bert_model.embed 170496 collect(sum(bert_embedding, dims=2)[:]) - end
, . , , , , . , . .
— :
julia --project=@. --code-coverage --track-allocation test/runtests.jl
— Profile.jl
@profile
. https://julialang.org/blog/2019/09/profilers . @noinline
, . , fib
fib_r
.
julia> @noinline function fib(n) return n > 1 ? fib_r(n - 1) + fib_r(n - 2) : 1 end julia> @noinline fib_r(n) = fib(n) julia> @time fib(40) 0.738735 seconds (3.16 k allocations: 176.626 KiB) 165580141 julia> using Profile julia> @profile fib(40) 165580141 julia> Profile.print(format=:flat, sortedby=:count) Count File Line Function 12 int.jl 52 - 14 int.jl 53 + 212 boot.jl 330 eval 5717 REPL[2] 1 fib_r 6028 REPL[1] 2 fib julia> count(==(0), Profile.fetch()) 585
@profile fib(40)
. Profile.print(format=:flat, sortedby=:count)
. , , , fib_r
fib
, . , :
julia> Profile.print(format=:tree) 260 REPL[1]:2; fib(::Int64) 112 REPL[1]:1; fib_r(::Int64) 212 task.jl:333; REPL.var"##26#27" 212 REPL.jl:118; macro expansion 212 REPL.jl:86; eval_user_input 212 boot.jl:330; eval ╎ 210 REPL[1]:2; fib ╎ 210 REPL[1]:1; fib_r ╎ 210 REPL[1]:2; fib ╎ 210 REPL[1]:1; fib_r ╎ 210 REPL[1]:2; fib ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ 210 REPL[1]:2; fib ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ 210 REPL[1]:2; fib ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ ╎ 210 REPL[1]:2; fib ╎ ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ ╎ 210 REPL[1]:2; fib ╎ ╎ ╎ 210 REPL[1]:1; fib_r ╎ ╎ ╎ 210 REPL[1]:2; fib ...
. PProf.jl, .

. https://github.com/vchuravy/PProf.jl .
doc
. https://habr.com/ru/post/439442/
, , Julia .
Project.toml
, . , , - , , .
, , . , — . :
, , . , , git clone, . PackageCompiler.jl
. , , - .
C
- , , ( - , ), deps, deps/build.jl
. . , , , . , , , , . , , build.jl
, :
. julia --project=@.
Julia Project.toml
. , — build.jl
, executable
. , julia --project=@. build.jl
.
Pkg.activate(".")
( Project.toml
).
Pkg.build()
, C-, . deps/build.jl
, .
Pkg.test()
. , -, , . -, , . coverage=true
. , . build.jl
.
, . , PkgTempletes
. — Gitlab CI, Travis CI, GitHub , .
Fazit
, , Julia. , , . , — , -, , . , .
Referenzen