


In diesem Blogbeitrag vergleichen wir die Leistung von drei verschiedenen Algorithmen, die in einem aktuellen persönlichen Projekt verwendet wurden: dem ILP (Integer Linear Programming)-Algorithmus, dem Lokaler Algorithmus unter Verwendung des A*-Algorithmus und eine optimierte Lösung unter Verwendung des Branch and Bound-Algorithmus. Alle Algorithmen wurden mit demselben Datensatz getestet, wobei die ILP- und Branch-and-Bound-Implementierungen die gleiche Arbeitslast teilten, während die A*-Implementierung aufgrund von Leistungseinschränkungen eingeschränkt war.
Haftungsausschluss: Obwohl ich nicht auf die spezifischen Codedetails des Projekts eingehen werde, werde ich einige Erkenntnisse daraus teilen. Die Codebasis ist nicht zur öffentlichen Offenlegung bestimmt und dient als Haftungsausschluss zur Wahrung ihrer Vertraulichkeit.
Benchmark-Ergebnisse
Hier sind die Benchmark-Ergebnisse für alle drei Algorithmen:
goos: linux goarch: amd64 pkg: github.com/sosalejandro/<my-project>/<my-package>/pkg cpu: 13th Gen Intel(R) Core(TM) i7-13700HX BenchmarkGenerateReportILP-24 724 1694029 ns/op 30332 B/op 181 allocs/op BenchmarkGenerateReportILPParallel-24 6512 187871 ns/op 34545 B/op 184 allocs/op BenchmarkGenerateReportLocal-24 2 851314106 ns/op 559466456 B/op 7379756 allocs/op BenchmarkBranchGenerateReportLocal-24 101449 12106 ns/op 29932 B/op 165 allocs/op BenchmarkGenerateReportLocalParallel-24 3 349605952 ns/op 559422440 B/op 7379837 allocs/op BenchmarkBranchGenerateReportLocalParallel-24 120543 10755 ns/op 29933 B/op 165 allocs/op PASS coverage: 81.4% of statements ok github.com/sosalejandro/<my-project>/<my-package>/pkg 11.121s </my-package></my-project></my-package></my-project>
Workload-Konfiguration
Alle Algorithmen wurden mit demselben Datensatz getestet, aber der Arbeitsaufwand (d. h. die Häufigkeit, mit der jedes Element verarbeitet wird) unterschied sich zwischen den Implementierungen.
ILP- und Branch-and-Bound-Implementierungsarbeitsaufwand:
plan := []Plan{ {ID: "1", Times: 100}, {ID: "2", Times: 150}, {ID: "3", Times: 200}, {ID: "8", Times: 50}, {ID: "9", Times: 75}, {ID: "10", Times: 80}, {ID: "11", Times: 90}, {ID: "12", Times: 85}, {ID: "13", Times: 60}, {ID: "14", Times: 110}, }
A* Implementierungsaufwand:
plan := []Plan{ {ID: "1", Times: 1}, {ID: "2", Times: 1}, {ID: "3", Times: 5}, {ID: "8", Times: 5}, {ID: "9", Times: 5}, {ID: "10", Times: 5}, {ID: "11", Times: 9}, {ID: "12", Times: 5}, {ID: "13", Times: 5}, {ID: "14", Times: 5}, }
Workload-Analyse
Um die Auswirkungen dieser Arbeitslasten auf die Benchmark-Ergebnisse zu verstehen, berechnen wir die Gesamtzahl der Iterationen (d. h. die Summe der Zeitwerte) für jede Implementierung.
Gesamtzahl der Iterationen:
- ILP und Branch-and-Bound-Implementierungen:
100 + 150 + 200 + 50 + 75 + 80 + 90 + 85 + 60 + 110 = 1000
- A*-Implementierung:
1 + 1 + 5 + 5 + 5 + 5 + 9 + 5 + 5 + 5 = 46
Arbeitsbelastungsverhältnis:
ILP Iterations / A* Iterations = 1000 / 46 ≈ 21.74
Das bedeutet, dass die ILP- und Branch-and-Bound-Implementierungen ungefähr 21,74-mal mehr Iterationen verarbeiten im Vergleich zur A*-Implementierung.
Leistungsvergleich
Lassen Sie uns die Benchmark-Ergebnisse in Bezug auf die Arbeitsbelastungsunterschiede aufschlüsseln.
Benchmark | Runs | ns/op | B/op | allocs/op | Total Time (ns) |
---|---|---|---|---|---|
BenchmarkGenerateReportILP-24 | 724 | 1,694,029 | 30,332 | 181 | ≈ 1,225,836,996 |
BenchmarkGenerateReportILPParallel-24 | 6,512 | 187,871 | 34,545 | 184 | ≈ 1,223,607,552 |
BenchmarkBranchGenerateReportLocal-24 | 101,449 | 12,106 | 29,932 | 165 | ≈ 1,224,505,394 |
BenchmarkGenerateReportLocal-24 | 2 | 851,314,106 | 559,466,456 | 7,379,756 | ≈ 1,702,628,212 |
BenchmarkGenerateReportLocalParallel-24 | 3 | 349,605,952 | 559,422,440 | 7,379,837 | ≈ 1,048,817,856 |
BenchmarkBranchGenerateReportLocalParallel-24 | 120,543 | 10,755 | 29,933 | 165 | ≈ 1,295,219,065 |
Beobachtungen
-
Ausführungszeit pro Vorgang:
-
BenchmarkGenerateReportILP-24 vs. BenchmarkBranchGenerateReportLocal-24:
- Branch and Bound ist 99,29 % schneller als ILP und reduziert die Ausführungszeit von 1.694.029 ns/op auf 12.106 ns/op .
-
BenchmarkGenerateReportILP-24 vs. BenchmarkBranchGenerateReportLocal-24:
-
BenchmarkGenerateReportILP-24 vs BenchmarkGenerateReportLocal-24:
- ILP ist 99,80 % schneller als Local und reduziert die Ausführungszeit von 851.314.106 ns/op auf 1.694.029 ns/op.
-
BenchmarkGenerateReportILPParallel-24 vs BenchmarkBranchGenerateReportLocalParallel-24:
- Branch and Bound Parallel ist 94,28 % schneller als ILP Parallel und reduziert die Ausführungszeit von 187.871 ns/op auf 10.755 ns /op.
-
BenchmarkGenerateReportILPParallel-24 vs. BenchmarkGenerateReportLocalParallel-24:
- ILP Parallel ist 99,95 % schneller als Local Parallel und reduziert die Ausführungszeit von 349.605.952 ns/op auf 187.871 ns/op .
-
Speicherzuweisungen:
- ILP-Implementierungen:Leichter Anstieg der Speichernutzung und -zuweisungen bei paralleler Ausführung.
- Branch-and-Bound-Implementierungen: Geringere Speichernutzung und -zuweisungen im Vergleich zu den A*-Implementierungen.
- A*-Implementierungen: Extrem hohe Speicherzuweisungen, was zu einer ineffizienten Ressourcennutzung führt.
-
Durchsatz:
- ILP Parallel und Branch and Bound Parallel können aufgrund der höheren Arbeitsbelastung ungefähr 21,74-mal mehr Iterationen verarbeiten.
- A*-Implementierungen haben Probleme mit dem Durchsatz, nicht aufgrund der deutlich geringeren Anzahl von Iterationen, sondern aufgrund der ineffizienten Speichernutzung und Implementierung.
Auswirkungen unterschiedlicher Arbeitsbelastung auf die Leistung
Angesichts der Tatsache, dass die ILP- und Branch-Algorithmen 21,74-mal mehr Durchsatz pro Testiteration verarbeiten, wirkt sich dieser Unterschied in der Arbeitslast auf die Leistung und Effizienz jedes Algorithmus aus:
ILP- und Branch-Algorithmen: Da diese einen größeren Durchsatz bewältigen, sind sie für höhere Arbeitslasten optimiert. Obwohl sie mehr Vorgänge abwickeln, sorgen sie für kürzere Ausführungszeiten. Dies legt nahe, dass sie nicht nur recheneffizient sind, sondern auch für Hochdurchsatzszenarien gut geeignet sind.
Lokaler Algorithmus: Mit einem geringeren Durchsatz und einer höheren Ausführungszeit ist dieser Algorithmus bei der Bewältigung erhöhter Arbeitslasten weniger effizient. Bei einer Skalierung auf den gleichen Durchsatz wie ILP oder Branch würde sich die Ausführungszeit erheblich verlängern, was darauf hindeutet, dass es nicht ideal für Fälle mit hohem Durchsatz ist.
In Szenarien mit erhöhter Arbeitslast würden ILP und Branch Local übertreffen aufgrund ihrer Fähigkeit, einen höheren Durchsatz effizient zu verwalten. Wenn umgekehrt die Arbeitslast reduziert würde, könnte die Leistung des lokalen Algorithmus näher an der von ILP und Branch liegen, würde aber aufgrund grundlegender Unterschiede in der Algorithmuseffizienz wahrscheinlich immer noch hinterherhinken.
Algorithmusübersicht
Um ein klareres Verständnis dafür zu vermitteln, wie die einzelnen Algorithmen an die Problemlösung herangehen, finden Sie hier einen allgemeinen Überblick über ihre Mechanismen und Methoden.
Ganzzahlige lineare Programmierung (ILP)
Zweck:
ILP ist eine Optimierungstechnik, mit der das beste Ergebnis (z. B. maximaler Gewinn oder niedrigste Kosten) in einem mathematischen Modell ermittelt wird, dessen Anforderungen durch lineare Beziehungen dargestellt werden. Es ist besonders effektiv für Probleme, die durch lineare Einschränkungen und eine lineare Zielfunktion ausgedrückt werden können.
Allgemeiner Arbeitsablauf:
Variablen definieren:
Identifizieren Sie die Entscheidungsvariablen, die die zu treffenden Entscheidungen darstellen.Zielfunktion:
Formulieren Sie eine lineare Gleichung, die maximiert oder minimiert werden muss.Einschränkungen:
Legen Sie lineare Ungleichungen oder Gleichheiten fest, die die Lösung erfüllen muss.Lösen:
Verwenden Sie einen ILP-Löser, um die optimalen Werte der Entscheidungsvariablen zu finden, die die Zielfunktion maximieren oder minimieren und gleichzeitig alle Einschränkungen erfüllen.
Pseudocode:
goos: linux goarch: amd64 pkg: github.com/sosalejandro/<my-project>/<my-package>/pkg cpu: 13th Gen Intel(R) Core(TM) i7-13700HX BenchmarkGenerateReportILP-24 724 1694029 ns/op 30332 B/op 181 allocs/op BenchmarkGenerateReportILPParallel-24 6512 187871 ns/op 34545 B/op 184 allocs/op BenchmarkGenerateReportLocal-24 2 851314106 ns/op 559466456 B/op 7379756 allocs/op BenchmarkBranchGenerateReportLocal-24 101449 12106 ns/op 29932 B/op 165 allocs/op BenchmarkGenerateReportLocalParallel-24 3 349605952 ns/op 559422440 B/op 7379837 allocs/op BenchmarkBranchGenerateReportLocalParallel-24 120543 10755 ns/op 29933 B/op 165 allocs/op PASS coverage: 81.4% of statements ok github.com/sosalejandro/<my-project>/<my-package>/pkg 11.121s </my-package></my-project></my-package></my-project>
A*-Algorithmus (lokale Implementierung)
Zweck:
A* ist ein Pfadfindungs- und Graph-Traversal-Algorithmus, der für seine Leistung und Genauigkeit bekannt ist. Es findet effizient den kürzesten Weg zwischen Knoten, indem es Funktionen der Suche nach einheitlichen Kosten und der reinen heuristischen Suche kombiniert.
Allgemeiner Arbeitsablauf:
Initialisierung:
Beginnen Sie mit einem Anfangsknoten und fügen Sie ihn der Prioritätswarteschlange hinzu.-
Schleife:
- Entfernen Sie den Knoten mit der niedrigsten Kostenschätzung aus der Prioritätswarteschlange.
- Wenn es sich um den Zielknoten handelt, beenden Sie ihn.
- Andernfalls erweitern Sie den Knoten, indem Sie seine Nachbarn erkunden.
- Berechnen Sie für jeden Nachbarn die neuen Kosten und aktualisieren Sie die Prioritätswarteschlange entsprechend.
Kündigung:
Der Algorithmus schließt ab, wenn der Zielknoten erreicht ist oder die Prioritätswarteschlange leer ist (was anzeigt, dass kein Pfad vorhanden ist).
Pseudocode:
goos: linux goarch: amd64 pkg: github.com/sosalejandro/<my-project>/<my-package>/pkg cpu: 13th Gen Intel(R) Core(TM) i7-13700HX BenchmarkGenerateReportILP-24 724 1694029 ns/op 30332 B/op 181 allocs/op BenchmarkGenerateReportILPParallel-24 6512 187871 ns/op 34545 B/op 184 allocs/op BenchmarkGenerateReportLocal-24 2 851314106 ns/op 559466456 B/op 7379756 allocs/op BenchmarkBranchGenerateReportLocal-24 101449 12106 ns/op 29932 B/op 165 allocs/op BenchmarkGenerateReportLocalParallel-24 3 349605952 ns/op 559422440 B/op 7379837 allocs/op BenchmarkBranchGenerateReportLocalParallel-24 120543 10755 ns/op 29933 B/op 165 allocs/op PASS coverage: 81.4% of statements ok github.com/sosalejandro/<my-project>/<my-package>/pkg 11.121s </my-package></my-project></my-package></my-project>
Branch-and-Bound-Algorithmus
Zweck:
Branch and Bound ist ein Optimierungsalgorithmus, der den Lösungsraum systematisch erkundet. Es unterteilt das Problem in kleinere Teilprobleme (Verzweigung) und verwendet Grenzen, um Teilprobleme zu eliminieren, die keine besseren Lösungen als die derzeit besten liefern können (Begrenzung).
Allgemeiner Arbeitsablauf:
Initialisierung:
Beginnen Sie mit einer ersten Lösung und legen Sie die bekannteste Lösung fest.Verzweigung:
Teilen Sie das Problem an jedem Knoten in kleinere Teilprobleme auf.Begrenzung:
Berechnen Sie eine optimistische Schätzung (Obergrenze) der bestmöglichen Lösung in jedem Zweig.Beschneiden:
Verwerfen Sie Zweige, bei denen die Obergrenze schlechter ist als die bekannteste Lösung.Suche:
Erkunden Sie verbleibende Zweige rekursiv mithilfe der Tiefensuche oder der Bestensuche.Kündigung:
Wenn alle Zweige beschnitten oder erkundet wurden, ist die bekannteste Lösung optimal.
Pseudocode:
goos: linux goarch: amd64 pkg: github.com/sosalejandro/<my-project>/<my-package>/pkg cpu: 13th Gen Intel(R) Core(TM) i7-13700HX BenchmarkGenerateReportILP-24 724 1694029 ns/op 30332 B/op 181 allocs/op BenchmarkGenerateReportILPParallel-24 6512 187871 ns/op 34545 B/op 184 allocs/op BenchmarkGenerateReportLocal-24 2 851314106 ns/op 559466456 B/op 7379756 allocs/op BenchmarkBranchGenerateReportLocal-24 101449 12106 ns/op 29932 B/op 165 allocs/op BenchmarkGenerateReportLocalParallel-24 3 349605952 ns/op 559422440 B/op 7379837 allocs/op BenchmarkBranchGenerateReportLocalParallel-24 120543 10755 ns/op 29933 B/op 165 allocs/op PASS coverage: 81.4% of statements ok github.com/sosalejandro/<my-project>/<my-package>/pkg 11.121s </my-package></my-project></my-package></my-project>
Vergleichende Analyse
Feature | ILP Implementation | Local (A*) Implementation | Branch and Bound Implementation |
---|---|---|---|
Optimization Approach | Formulates the problem as a set of linear equations and inequalities to find the optimal solution. | Searches through possible states using heuristics to find the most promising path to the goal. | Systematically explores and prunes the solution space to find optimal solutions efficiently. |
Scalability | Handles large-scale problems efficiently by leveraging optimized solvers. | Performance can degrade with increasing problem size due to the exhaustive nature of state exploration. | Efficient for combinatorial problems, with pruning reducing the search space significantly. |
Development Time | Faster implementation as it relies on existing ILP solvers and libraries. | Requires more time to implement, especially when dealing with complex state management and heuristics. | Moderate development time, balancing complexity and optimization benefits. |
Flexibility | Highly adaptable to various linear optimization problems with clear constraints and objectives. | Best suited for problems where pathfinding to a goal is essential, with heuristic guidance. | Effective for a wide range of optimization problems, especially combinatorial ones. |
Performance | Demonstrates superior performance in handling a higher number of iterations with optimized memory usage. | While effective for certain scenarios, struggles with high memory allocations and longer execution times under heavy workloads. | Shows significant performance improvements over ILP and A* with optimized memory usage and faster execution times. |
Developer Experience | Improves developer experience by reducing the need for extensive coding and optimization efforts. | May require significant debugging and optimization to achieve comparable performance levels. | Balances performance with manageable development effort, leveraging existing strategies for optimization. |
Integration | Currently integrates a C ILP module with Golang, facilitating efficient computation despite cross-language usage. | Fully implemented within Golang, but may face limitations in performance and scalability without optimizations. | Implemented in Golang, avoiding cross-language integration complexities and enhancing performance. |
Auswirkungen auf die Serverleistung
-
Skalierbarkeit:
- Die Branch and Bound-Implementierung zeigt eine hervorragende Skalierbarkeit und verarbeitet effizient eine große Anzahl gleichzeitiger Anfragen mit reduzierter Latenz.
- Die ILP Parallel-Implementierung zeigt außerdem eine hervorragende Skalierbarkeit und verarbeitet effizient eine große Anzahl gleichzeitiger Anfragen mit reduzierter Latenz.
- Die A*-Implementierung ist aufgrund von Leistungseinschränkungen für Umgebungen mit hoher Auslastung ungeeignet.
-
Ressourcennutzung:
- Branch-and-Bound-Implementierungen nutzen Ressourcen effizient, mit geringem Speicherverbrauch und schnellen Ausführungszeiten.
- ILP Parallel nutzt effektiv Multi-Core-CPUs und bietet so einen hohen Durchsatz bei überschaubarem Speicherverbrauch.
- A*-Implementierungen verbrauchen übermäßig viel Speicher, was möglicherweise zur Erschöpfung der Ressourcen führt.
Auswirkungen der Arbeitslast auf die Leistung
Die Workload-Unterschiede beeinflussen die Leistung der Algorithmen:
Branch-and-Bound-Implementierung bewältigt die gleiche Arbeitslast wie die ILP-Implementierung effizient und sorgt für schnelle Ausführungszeiten und geringe Speichernutzung, sodass sie für die Skalierung geeignet ist.
ILP-Implementierung bewältigt aufgrund optimierter Solver eine größere Arbeitslast effizient.
A*-Implementierung hat aufgrund hoher Ausführungszeiten und Speichernutzung Probleme mit der Leistung.
Abschluss
Ein zusätzlicher Vergleich wurde mit einer optimierten Lösung mit dem Branch and Bound-Algorithmus hinzugefügt, der zeigt, wie sich diese im Hinblick auf Leistung und Ressourcennutzung gegenüber dem ILP- und dem A*-Algorithmus deutlich verbessert hat. Die beim Branch-and-Bound-Algorithmus verwendete Arbeitslast ist die gleiche wie beim ILP-Algorithmus.
Die Branch and Bound-basierte BenchmarkBranchGenerateReportLocalParallel-Funktion weist außergewöhnliche Leistungsverbesserungen auf und eignet sich daher hervorragend für Serverumgebungen, die eine hohe Parallelität und effizientes Ressourcenmanagement erfordern.
Indem wir uns darauf konzentrieren, die Stärken des Branch-and-Bound-Ansatzes zu nutzen und ihn für das spezifische Problem zu optimieren, können wir sicherstellen, dass das Projekt sowohl leistungsfähig als auch skalierbar bleibt und in der Lage ist, steigende Anforderungen problemlos zu bewältigen.
Letzte Gedanken
Das Gleichgewicht zwischen Leistung, Skalierbarkeit und Entwicklererfahrung ist entscheidend für die Entwicklung robuster Anwendungen. Der Branch and Bound-Ansatz hat sich im aktuellen Setup als der effizienteste erwiesen und bietet erhebliche Leistungssteigerungen bei vertretbarem Entwicklungsaufwand.
Durch die kontinuierliche Profilierung, Optimierung und Nutzung der Stärken jedes algorithmischen Ansatzes können wir ein leistungsstarkes, skalierbares und entwicklerfreundliches System aufrechterhalten.
Das obige ist der detaillierte Inhalt vonVergleichendes Benchmarking: ILP-, A*- und Branch-and-Bound-Algorithmen in Hochdurchsatzszenarien. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

GoisastrongchoiceForProjectSeNeedingImplication, Leistung und Konkurrenz, ButitmaylackinadvancedFeatures undcosystemmaturity.1) Go'SSYNTAXISMPEANDEALEDELTOLEARN, FEHTTOFEWERBUGSANDMOREMINTAINABLECODE, obwohl es sich

Go'Sinitfunctionandjava'SstaticInitializersBothServetosetupenvironmentBeforethemaNfunction, Buttheydifferinexexcution undControl

ThecommonusecasesFortheinitfunctioningoare: 1) LadekonfigurationsfiguresbeforethemaProgramstarts, 2) Initialisierungsglobalvariablen und 3) RunningPre-ChecksorvalidationsBeforTheProgramProcececececeers.

ChannelsarecrucialingoforenablingsAfeAnDefficienceCommunicationBetweengoroutines.TheyfacilitateSynchronizationAndManageGoroutinElifecycle, EssentialforcurrentProgramming.ChannelsallowsendingandReceive -Values, ActaStarnalsforsynchronisierungen und Subors

In Go können Fehler verpackt und ein Kontext über Fehler hinzugefügt werden. 1) Mit der neuen Funktion des Fehlerpakets können Sie während der Fehlerausbreitung Kontextinformationen hinzufügen. 2) Helfen Sie dabei, das Problem zu lokalisieren, indem Sie Fehler über FMT.Errorf und %W einwickeln. 3) Benutzerdefinierte Fehlertypen können mehr semantische Fehler erzeugen und die ausdrucksstarke Fähigkeit der Fehlerbehandlung verbessern.

GooffersrobustFeaturesForsecurecoding, butdeveloperMustimplementsCurityBestPracticeSeffective.1) UseGo'ScryptopackageForScedatahandling.2) ManageConcurrencywithsynchronizationPrimitivestopreventraceconcitions.3) Sanitendien.3) HANNISITEPERCEEPERCEEPERCEEPERSCEEDEEXTERSEXTERSUCHE

Die Fehlerschnittstelle von GO ist als TypeErrorInterface {error () String} definiert, sodass jeder Typ, der die Fehler (ERROR () -Methode implementiert, als Fehler angesehen werden kann. Die Verwendung für die Verwendung sind wie folgt: 1. Überprüfen Sie im Grunde genommen Fehler und Protokollfehler, wie z. 2. Erstellen Sie einen benutzerdefinierten Fehlertyp, um weitere Informationen bereitzustellen, z. 3. Verwenden Sie Fehlerverpackungen (seit Go1.13), um den Kontext hinzuzufügen, ohne die ursprüngliche Fehlermeldung zu verlieren.

TOEFFEKTIVE HANDLEERSINCONCURENTGOPROGRAMMEN, UsechannelstocommunicateErrors, ImplementErrorWatchers, Considertimeouts, UseBiftedChannels und ProvideClearErrormessages.1) Usechannelstopassirrorsfromgoroutinestothänenfunktion.2) ImplementanerErrorWesser


Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

WebStorm-Mac-Version
Nützliche JavaScript-Entwicklungstools

DVWA
Damn Vulnerable Web App (DVWA) ist eine PHP/MySQL-Webanwendung, die sehr anfällig ist. Seine Hauptziele bestehen darin, Sicherheitsexperten dabei zu helfen, ihre Fähigkeiten und Tools in einem rechtlichen Umfeld zu testen, Webentwicklern dabei zu helfen, den Prozess der Sicherung von Webanwendungen besser zu verstehen, und Lehrern/Schülern dabei zu helfen, in einer Unterrichtsumgebung Webanwendungen zu lehren/lernen Sicherheit. Das Ziel von DVWA besteht darin, einige der häufigsten Web-Schwachstellen über eine einfache und unkomplizierte Benutzeroberfläche mit unterschiedlichen Schwierigkeitsgraden zu üben. Bitte beachten Sie, dass diese Software

ZendStudio 13.5.1 Mac
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Herunterladen der Mac-Version des Atom-Editors
Der beliebteste Open-Source-Editor

Dreamweaver CS6
Visuelle Webentwicklungstools
