ML -Ingenieure und Softwareentwickler, die jede Leistung unserer Codebasen optimieren, kann eine entscheidende Überlegung sein. Wenn Sie ein Python -Benutzer sind, werden Sie in dieser Hinsicht einige seiner Defizite bewusst. Python gilt als langsame Sprache, und Sie haben wahrscheinlich gehört, dass ein Großteil des Grundes auf den GIL -Mechanismus (International Interpreter Lock) zurückzuführen ist.

Es ist was es ist, aber was können wir dagegen tun? Es gibt verschiedene Möglichkeiten, wie wir dieses Drawback beim Codieren in Python verbessern können, insbesondere wenn Sie eine einigermaßen aktuelle Model von Python verwenden.

  • Die neuesten Veröffentlichungen von Python haben eine Möglichkeit, Code ohne Verwendung des GIL auszuführen.
  • Wir können Hochleistungsbibliotheken von Drittanbietern wie Numpy verwenden, um die Zahlenknackung durchzuführen.
  • Es gibt auch viele Methoden zur parallele und gleichzeitigen Verarbeitung in die Sprache.

Eine weitere Methode, die wir verwenden können, besteht darin, andere Hochleistungssprachen innerhalb von Python für zeitkritische Abschnitte unseres Codes aufzurufen. Das werden wir in diesem Artikel behandeln, wenn ich Ihnen zeige, wie Sie anrufen Mojo Code von Python.

Hast du schon schon von Mojo gehört? Wenn nicht, finden Sie hier eine kurze Geschichtsstunde.

Mojo ist eine relativ neue Sprache auf Systemebene, die von Modular Inc entwickelt wurde. (Ein AI-Infrastrukturunternehmen, das 2022 von Compiler Writing Legend mitbegründet wurde Chris Lattner, von LLVM und Swift Creator Fame und ehemaliger Google TPUs Lead Tim Davis) und zuerst öffentlich in gezeigt in Mai 2023.

Es wurde aus einem einfachen Schmerzpunkt geboren, dh Pythons mangelnde Leistung, die wir zuvor besprochen hatten. Mojo geht dieses Frontal durch, indem es eine Superset von Pythons Syntax auf eine LLVM/MLIR-basierte Compiler-Pipeline transplantiert, die keine Kostenabstraktionen, statische Typisierung, Eigentümerspeichermanagement, automatische Vektorisation und nahtlose Codegenerierung für CPU- und GPU-Beschleuniger liefert.

Frühe Benchmarks, die beim Begin demonstrierten 35.000 × schneller als Vanille -Python, der beweist, dass Mojo den rohen Durchsatz von C/CUDA übereinstimmen oder übertreffen kann, während Entwickler in einem vertrauten „pythonischen“ Territorium bleiben können.

Es gibt jedoch immer einen Stolperstein, und das ist die Trägheit der Leute, sich vollständig in eine neue Sprache zu bewegen. Ich bin auch einer dieser Leute, additionally conflict ich erfreut, als ich las, dass es jetzt vor ein paar Wochen den Mojo -Code direkt von Python anrufen konnte.

Bedeutet das, dass wir das Beste aus beiden Welten bekommen: die Einfachheit von Python und die Leistung von Mojo?

Um die Behauptungen zu testen, schreiben wir einen Code mit Vanilla Python. Für jeden werden wir auch eine Model mit Numpy und schließlich einer Python -Model codieren, die einen Teil ihrer Berechnung zu einem Mojo -Modul auslädt. Letztendlich vergleichen wir die verschiedenen Laufzeiten.

Werden wir erhebliche Leistungssteigerungen sehen? Lesen Sie weiter, um es herauszufinden.

Einrichtung einer Entwicklungsumgebung

Ich werde WSL2 Ubuntu für Home windows für meine Entwicklung verwenden. Die beste Praxis ist es, für jedes Projekt, an dem Sie arbeiten, eine neue Entwicklungsumgebung einzurichten. Normalerweise benutze ich Conda dafür, aber da sich alle und ihre Oma zu verwenden scheinen, die Neue zu benutzen UV Packungsmanager, ich werde es stattdessen versuchen. Es gibt einige Möglichkeiten, wie Sie UV installieren können.

$ curl -LsSf https://astral.sh/uv/set up.sh | sh

or...

$ pip set up uv

Als nächstes ein Projekt initialisieren.

$ uv init mojo-test 
$ cd mojo-test
$ uv venv
$ supply .venv/bin/activate

Initialized venture `mojo-test` at `/residence/tom/initiatives/mojo-test`
(mojo-test) $ cd mojo-test
(mojo-test) $ ls -al
complete 28
drwxr-xr-x  3 tom tom 4096 Jun 27 09:20 .
drwxr-xr-x 15 tom tom 4096 Jun 27 09:20 ..
drwxr-xr-x  7 tom tom 4096 Jun 27 09:20 .git
-rw-r--r--  1 tom tom  109 Jun 27 09:20 .gitignore
-rw-r--r--  1 tom tom    5 Jun 27 09:20 .python-version
-rw-r--r--  1 tom tom    0 Jun 27 09:20 README.md
-rw-r--r--  1 tom tom   87 Jun 27 09:20 primary.py
-rw-r--r--  1 tom tom  155 Jun 27 09:20 pyproject.toml

Fügen Sie nun alle externen Bibliotheken hinzu, die wir brauchen

(mojo-test) $ uv pip set up modular numpy matplotlib

Wie funktioniert das Rufen von Mojo von Python?

Nehmen wir an, wir haben die folgende einfache Mojo -Funktion, die eine Python -Variable als Argument nimmt und zwei zu ihrem Wert hinzufügt. Zum Beispiel,

# mojo_func.mojo
#
fn add_two(py_obj: PythonObject) raises -> Python
    var n = Int(py_obj)
    return n + 2

Wenn Python versucht, add_two zu laden, sucht es nach einer Funktion namens Pyinit_add_two ()). Innerhalb von pyinit_add_two () müssen wir alle MOJO -Funktionen und -Typen deklarieren, die von Python mit dem abgerufen werden können Pythonmodulebuilder Bibliothek. Tatsächlich ähnelt unser Mojo -Code in seiner endgültigen Kind.

from python import PythonObject
from python.bindings import PythonModuleBuilder
from os import abort

@export
fn PyInit_mojo_module() -> PythonObject:
    strive:
        var m = PythonModuleBuilder("mojo_func")
        m.def_function(add_two)("add_two", docstring="Add 2 to n")
        return m.finalize()
    besides e:
        return abort(PythonObject)(String("Rrror creating Python Mojo module:", e))

fn add_two(py_obj: PythonObject) raises -> PythonObject:
    var n = Int(py_obj)
    n + 2

Der Python -Code benötigt einen zusätzlichen Boilerplate -Code, um korrekt zu funktionieren, wie hier gezeigt.

import max.mojo.importer
import sys

sys.path.insert(0, "")

import mojo_func

print(mojo_func.add_two(5))

# SHould print 7

Codebeispiele

Für jedes meiner Beispiele zeige ich drei verschiedene Versionen des Codes. Einer wird in reinem Python geschrieben, einer wird Numpy verwenden, um die Dinge zu beschleunigen, und der andere ersetzt gegebenenfalls Anrufe an Mojo.

Seien Sie gewarnt, dass das Anrufen von Mojo -Code von Python in der frühen Entwicklung ist. Sie können erhebliche Änderungen an der API und Ergonomie erwarten

Beispiel 1 – Berechnung eines Mandelbrot -Satzes

Für unser erstes Beispiel werden wir einen Mandelbrot -Set berechnen und anzeigen. Dies ist ziemlich rechnerisch teuer, und wie wir sehen werden, braucht die reine Python -Model viel Zeit, um abzuschließen.

Insgesamt benötigen wir insgesamt vier Dateien.

1/ mandelbrot_pure_py.py

# mandelbrot_pure_py.py
def compute(width, top, max_iters):
    """Generates a Mandelbrot set picture utilizing pure Python."""
    picture = ((0) * width for _ in vary(top))
    for row in vary(top):
        for col in vary(width):
            c = advanced(-2.0 + 3.0 * col / width, -1.5 + 3.0 * row / top)
            z = 0
            n = 0
            whereas abs(z) <= 2 and n < max_iters:
                z = z*z + c
                n += 1
            picture(row)(col) = n
    return picture

2/ mandelbrot_numpy.py

# mandelbrot_numpy.py

import numpy as np

def compute(width, top, max_iters):
    """Generates a Mandelbrot set utilizing NumPy for vectorized computation."""
    x = np.linspace(-2.0, 1.0, width)
    y = np.linspace(-1.5, 1.5, top)
    c = x(:, np.newaxis) + 1j * y(np.newaxis, :)
    z = np.zeros_like(c, dtype=np.complex128)
    picture = np.zeros(c.form, dtype=int)

    for n in vary(max_iters):
        not_diverged = np.abs(z) <= 2
        picture(not_diverged) = n
        z(not_diverged) = z(not_diverged)**2 + c(not_diverged)
        
    picture(np.abs(z) <= 2) = max_iters
    return picture.T

3/ mandelbrot_mojo.mojo

# mandelbrot_mojo.mojo 

from python import PythonObject, Python
from python.bindings import PythonModuleBuilder
from os import abort
from advanced import ComplexFloat64

# That is the core logic that can run quick in Mojo
fn compute_mandel_pixel(c: ComplexFloat64, max_iters: Int) -> Int:
    var z = ComplexFloat64(0, 0)
    var n: Int = 0
    whereas n < max_iters:
        # abs(z) > 2 is identical as z.norm() > 4, which is quicker
        if z.norm() > 4.0:
            break
        z = z * z + c
        n += 1
    return n

# That is the operate that Python will name
fn mandelbrot_mojo_compute(width_obj: PythonObject, height_obj: PythonObject, max_iters_obj: PythonObject) raises -> PythonObject:
    
    var width = Int(width_obj)
    var top = Int(height_obj)
    var max_iters = Int(max_iters_obj)

    # We are going to construct a Python checklist in Mojo to return the outcomes
    var image_list = Python.checklist()

    for row in vary(top):
        # We create a nested checklist to symbolize the 2D picture
        var row_list = Python.checklist()
        for col in vary(width):
            var c = ComplexFloat64(
                -2.0 + 3.0 * col / width,
                -1.5 + 3.0 * row / top
            )
            var n = compute_mandel_pixel(c, max_iters)
            row_list.append(n)
        
        image_list.append(row_list)
            
    return image_list

# That is the particular operate that "exports" our Mojo operate to Python
@export
fn PyInit_mandelbrot_mojo() -> PythonObject:
    strive:
       
        var m = PythonModuleBuilder("mandelbrot_mojo")
        m.def_function(mandelbrot_mojo_compute)("compute", "Generates a Mandelbrot set.")
        return m.finalize()
    besides e:
        return abort(PythonObject)("error creating mandelbrot_mojo module")

4/ primary.py

Dadurch werden die anderen drei Programme angerufen und es uns auch ermöglicht, das Mandelbrot -Diagramm in einem Jupyter -Notizbuch zu zeichnen. Ich werde die Handlung nur einmal zeigen. Sie müssen mein Wort nehmen, dass es in allen drei Läufen des Codes korrekt aufgetragen wurde.

# primary.py (Remaining model with visualization)

import time
import numpy as np
import sys

import matplotlib.pyplot as plt # Now, import pyplot

# --- Mojo Setup ---
strive:
    import max.mojo.importer
besides ImportError:
    print("Mojo importer not discovered. Please make sure the MODULAR_HOME and PATH are set accurately.")
    sys.exit(1)

sys.path.insert(0, "")

# --- Import Our Modules ---
import mandelbrot_pure_py
import mandelbrot_numpy
import mandelbrot_mojo

# --- Visualization Perform ---
def visualize_mandelbrot(image_data, title="Mandelbrot Set"):
    """Shows the Mandelbrot set information as a picture utilizing Matplotlib."""
    print(f"Displaying picture for: {title}")
    plt.determine(figsize=(10, 8))
    # 'scorching', 'inferno', and 'plasma' are all nice colormaps for this
    plt.imshow(image_data, cmap='scorching', interpolation='bicubic')
    plt.colorbar(label="Iterations")
    plt.title(title)
    plt.xlabel("Width")
    plt.ylabel("Top")
    plt.present()

# --- Take a look at Runner ---
def run_test(title, compute_func, *args):
    """A helper operate to run and time a take a look at."""
    print(f"Operating {title} model...")
    start_time = time.time()
    # The compute operate returns the picture information
    result_data = compute_func(*args)
    period = time.time() - start_time
    print(f"-> {title} model took: {period:.4f} seconds")
    # Return the info so we will visualize it
    return result_data

if __name__ == "__main__":
    WIDTH, HEIGHT, MAX_ITERS = 800, 600, 5000
    
    print("Beginning Mandelbrot efficiency comparability...")
    print("-" * 40)

    # Run Pure Python Take a look at
    py_image = run_test("Pure Python", mandelbrot_pure_py.compute, WIDTH, HEIGHT, MAX_ITERS)
    visualize_mandelbrot(py_image, "Pure Python Mandelbrot")

    print("-" * 40)

    # Run NumPy Take a look at
    np_image = run_test("NumPy", mandelbrot_numpy.compute, WIDTH, HEIGHT, MAX_ITERS)
    # uncomment the beneath line if you wish to see the plot
    #visualize_mandelbrot(np_image, "NumPy Mandelbrot")

    print("-" * 40)

    # Run Mojo Take a look at
    mojo_list_of_lists = run_test("Mojo", mandelbrot_mojo.compute, WIDTH, HEIGHT, MAX_ITERS)
    # Convert Mojo's checklist of lists right into a NumPy array for visualization
    mojo_image = np.array(mojo_list_of_lists)
    # uncomment the beneath line if you wish to see the plot  
    #visualize_mandelbrot(mojo_image, "Mojo Mandelbrot")

    print("-" * 40)
    print("Comparability full.")

Schließlich ist hier die Ausgabe.

Bild des Autors

Okay, das ist ein beeindruckender Begin für Mojo. Es conflict quick 20 -mal schneller als die reine Python -Implementierung und 5 -mal schneller als der Numpy -Code.

Beispiel 2 – Numerische Integration

In diesem Beispiel werden wir eine numerische Integration unter Verwendung der Regel von Simpson durchführen, um den Wert von sin (x) im Intervall 0 bis π zu bestimmen. Denken Sie daran, dass die Regel von Simpson eine Methode zur Berechnung eines ungefähren Wertes für ein Integral ist und ist definiert als.

∫ ≈ (h/3) * (f (x₀) + 4f (x₁) + 2f (x₂) + 4f (x₃) +… + 2f (xₙ-₂) + 4f (xₙ-₁) + f (xₙ))

Wo:

  • H ist die Breite jedes Schritts.
  • Die Gewichte betragen 1, 4, 2, 4, 2,…, 4, 1.
  • Die ersten und letzten Punkte haben ein Gewicht von 1.
  • Die Punkte bei seltsam Indizes haben ein Gewicht von 4.
  • Die Punkte bei sogar Indizes haben ein Gewicht von 2.

Der wahre Wert des Integrals, das wir berechnen möchten, ist zwei. Mal sehen, wie genau (und schnell) unsere Methoden sind.

Noch einmal brauchen wir vier Dateien.

1/ integration_pure_py.py

# integration_pure_py.py
import math

def compute(begin, finish, n):
    """Calculates the particular integral of sin(x) utilizing Simpson's rule."""
    if n % 2 != 0:
        n += 1 # Simpson's rule requires a good variety of intervals
    
    h = (finish - begin) / n
    integral = math.sin(begin) + math.sin(finish)

    for i in vary(1, n, 2):
        integral += 4 * math.sin(begin + i * h)
    
    for i in vary(2, n, 2):
        integral += 2 * math.sin(begin + i * h)
        
    integral *= h / 3
    return integral

2/ Integration_Numpy

# integration_numpy.py
import numpy as np

def compute(begin, finish, n):
    """Calculates the particular integral of sin(x) utilizing NumPy."""
    if n % 2 != 0:
        n += 1
    
    x = np.linspace(begin, finish, n + 1)
    y = np.sin(x)
    
    # Apply Simpson's rule weights: 1, 4, 2, 4, ..., 2, 4, 1
    integral = (y(0) + y(-1) + 4 * np.sum(y(1:-1:2)) + 2 * np.sum(y(2:-1:2)))
    
    h = (finish - begin) / n

3/ integration_mojo.mojo

# integration_mojo.mojo
from python import PythonObject, Python
from python.bindings import PythonModuleBuilder
from os import abort
from math import sin

# Word: The 'fn' key phrase is used right here because it's suitable with all variations.
fn compute_integral_mojo(start_obj: PythonObject, end_obj: PythonObject, n_obj: PythonObject) raises -> PythonObject:
    # Bridge crossing occurs ONCE in the beginning.
    var begin = Float64(start_obj)
    var finish = Float64(end_obj)
    var n = Int(n_obj)

    if n % 2 != 0:
        n += 1
    
    var h = (finish - begin) / n
    
    # All computation beneath is on NATIVE Mojo sorts. No Python interop.
    var integral = sin(begin) + sin(finish)

    # First loop for the '4 * f(x)' phrases
    var i_1: Int = 1
    whereas i_1 < n:
        integral += 4 * sin(begin + i_1 * h)
        i_1 += 2

    # Second loop for the '2 * f(x)' phrases
    var i_2: Int = 2
    whereas i_2 < n:
        integral += 2 * sin(begin + i_2 * h)
        i_2 += 2
        
    integral *= h / 3
    
    # Bridge crossing occurs ONCE on the finish.
    return Python.float(integral)

@export
fn PyInit_integration_mojo() -> PythonObject:
    strive:
        var m = PythonModuleBuilder("integration_mojo")
        m.def_function(compute_integral_mojo)("compute", "Calculates a particular integral in Mojo.")
        return m.finalize()
    besides e:
        return abort(PythonObject)("error creating integration_mojo module")

4/ primary.py

import time
import sys
import numpy as np

# --- Mojo Setup ---
strive:
    import max.mojo.importer
besides ImportError:
    print("Mojo importer not discovered. Please guarantee your setting is about up accurately.")
    sys.exit(1)
sys.path.insert(0, "")

# --- Import Our Modules ---
import integration_pure_py
import integration_numpy
import integration_mojo

# --- Take a look at Runner ---
def run_test(title, compute_func, *args):
    print(f"Operating {title} model...")
    start_time = time.time()
    end result = compute_func(*args)
    period = time.time() - start_time
    print(f"-> {title} model took: {period:.4f} seconds")
    print(f"   Consequence: {end result}")

# --- Major Take a look at Execution ---
if __name__ == "__main__":
    # Use a really massive variety of steps to focus on loop efficiency
    START = 0.0
    END = np.pi 
    NUM_STEPS = 100_000_000 # 100 million steps
    
    print(f"Calculating integral of sin(x) from {START} to {END:.2f} with {NUM_STEPS:,} steps...")
    print("-" * 50)

    run_test("Pure Python", integration_pure_py.compute, START, END, NUM_STEPS)
    print("-" * 50)
    run_test("NumPy", integration_numpy.compute, START, END, NUM_STEPS)
    print("-" * 50)
    run_test("Mojo", integration_mojo.compute, START, END, NUM_STEPS)
    print("-" * 50)
    print("Comparability full.")

Und die Ergebnisse?

Calculating integral of sin(x) from 0.0 to three.14 with 100,000,000 steps...
--------------------------------------------------
Operating Pure Python model...
-> Pure Python model took: 4.9484 seconds
   Consequence: 2.0000000000000346
--------------------------------------------------
Operating NumPy model...
-> NumPy model took: 0.7425 seconds
   Consequence: 1.9999999999999998
--------------------------------------------------
Operating Mojo model...
-> Mojo model took: 0.8902 seconds
   Consequence: 2.0000000000000346
--------------------------------------------------
Comparability full.

Es ist interessant, dass der Numpy -Code diesmal geringfügig schneller conflict als der Mojo -Code und sein endgültiger Wert genauer. Dies unterstreicht ein Schlüsselkonzept im Hochleistungs-Computing: den Kompromiss zwischen Vektorisierungs- und JIT-kompilierte Schleifen.

Numpys Stärke liegt in seiner Fähigkeit, Operationen zu vektorisieren. Es weist einen großen Speicherblock zu und nennt dann hoch optimierte, vorkompilierte C-Code, der moderne CPU-Funktionen wie SIMD nutzt, um die SIN () -Funktion auf Millionen von Werten gleichzeitig auszuführen. Diese „Burst -Verarbeitung“ ist unglaublich effizient.

MOJO hingegen nimmt unsere einfache, während der Schleife und JIT zusammen, um sie in hocheffizienten Maschinencode zu versetzen. Während dies die große anfängliche Speicherzuweisung von Numpy vermeidet, gab es in diesem spezifischen Fall die rohe Kraft von Numpys Vektorisierung eine leichte Kante.

Beispiel 3 – die Sigmoidfunktion

Die Sigmoidfunktion ist ein wichtiges Konzept in der KI, da es sich um den Eckpfeiler der binären Klassifizierung handelt.

Auch als logistische Funktion bezeichnet, ist sie so definiert.

Die Sigmoidfunktion nimmt alle echten Eingänge x und „Kürbis“ reibungslos in das offene Intervall (0,1) ein. In einfachen Worten, egal was an die Sigmoidfunktion übergeben wird, gibt es immer einen Wert zwischen 0 und 1 zurück.

Additionally zum Beispiel,

S(-197865) = 0
S(-2) = 0.0009111
S(3) = 0.9525741
S(10776.87) = 1

Dies macht es perfekt, um bestimmte Dinge wie Wahrscheinlichkeiten darzustellen.

Da der Python -Code einfacher ist, können wir ihn in das Benchmarking -Skript aufnehmen, sodass wir diesmal nur zwei Dateien haben.

Sigmaid_Mojo.mojo

from python               import Python, PythonObject
from python.bindings      import PythonModuleBuilder
from os                   import abort
from math                 import exp
from time                 import perf_counter

# ----------------------------------------------------------------------
#   Quick Mojo routine (no Python calls inside)
# ----------------------------------------------------------------------
fn sigmoid_sum(n: Int) -> (Float64, Float64):
    # deterministic fill, sized as soon as
    var information = Record(Float64)(size = n, fill = 0.0)
    for i in vary(n):
        information(i) = (Float64(i) / Float64(n)) * 10.0 - 5.0   # (-5, +5)

    var t0: Float64 = perf_counter()
    var complete: Float64 = 0.0
    for x in information:                       # single tight loop
        complete += 1.0 / (1.0 + exp(-x))
    var elapsed: Float64 = perf_counter() - t0
    return (complete, elapsed)

# ----------------------------------------------------------------------
#   Python-visible wrapper
# ----------------------------------------------------------------------
fn py_sigmoid_sum(n_obj: PythonObject) raises -> PythonObject:
    var n: Int = Int(n_obj)                        # validates arg
    var (tot, secs) = sigmoid_sum(n)

    # most secure container: construct a Python checklist (auto-boxes scalars)
    var out = Python.checklist()
    out.append(tot)
    out.append(secs)
    return out                                     # -> PythonObject

# ----------------------------------------------------------------------
#   Module initialiser  (title should match:  PyInit_sigmoid_mojo)
# ----------------------------------------------------------------------
@export
fn PyInit_sigmoid_mojo() -> PythonObject:
    strive:
        var m = PythonModuleBuilder("sigmoid_mojo")
        m.def_function(py_sigmoid_sum)(
            "sigmoid_sum",
            "Return (total_sigmoid, elapsed_seconds)"
        )
        return m.finalize()
    besides e:
        # if something raises, give Python an actual ImportError
        return abort(PythonObject)("error creating sigmoid_mojo module")

primary.py

# bench_sigmoid.py
import time, math, numpy as np

N = 50_000_000  

# --------------------------- pure-Python -----------------------------------
py_data = ((i / N) * 10.0 - 5.0 for i in vary(N))
t0 = time.perf_counter()
py_total = sum(1 / (1 + math.exp(-x)) for x in py_data)
print(f"Pure-Python : {time.perf_counter()-t0:6.3f} s  - Σσ={py_total:,.1f}")

# --------------------------- NumPy -----------------------------------------
np_data = np.linspace(-5.0, 5.0, N, dtype=np.float64)
t0 = time.perf_counter()
np_total = float(np.sum(1 / (1 + np.exp(-np_data))))
print(f"NumPy       : {time.perf_counter()-t0:6.3f} s  - Σσ={np_total:,.1f}")

# --------------------------- Mojo ------------------------------------------
import max.mojo.importer          # installs .mojo import hook
import sigmoid_mojo               # compiles & masses shared object

mj_total, mj_secs = sigmoid_mojo.sigmoid_sum(N)
print(f"Mojo        : {mj_secs:6.3f} s  - Σσ={mj_total:,.1f}")

Hier ist die Ausgabe.

$ python sigmoid_bench.py
Pure-Python :  1.847 s  - Σσ=24,999,999.5
NumPy       :  0.323 s  - Σσ=25,000,000.0
Mojo        :  0.150 s  - Σσ=24,999,999.5

Der Σσ =… Die Ausgänge zeigen die Summe aller berechneten Sigmoidwerte. Theoretisch sollte dies genau gleich dem Eingang n dividiert durch 2 sein, da N zur Unendlichkeit neigt.

Aber wie wir sehen, stellt die Mojo -Implementierung eine anständige Anhebung von über 2x auf dem bereits schnellen Numpy -Code dar und ist schneller als 12x schneller als die Implementierung von Basispython.

Nicht zu schäbig.

Zusammenfassung

In diesem Artikel wurde die aufregende neue Fähigkeit untersucht, Hochleistungs-Mojo-Code direkt aus Python zu bezeichnen, um rechenintensive Aufgaben zu beschleunigen. Mojo, eine relativ neue Systemprogrammiersprache von Modular, verspricht die Leistung auf C-Ebene mit einer vertrauten pythonischen Syntax, die darauf abzielt, die historischen Geschwindigkeitsbeschränkungen von Python zu lösen.

Um dieses Versprechen zu testen, haben wir drei rechnerisch teure Szenarien verabreicht: Mandelbrot-Set-Generierung, numerische Integration und die Sigmoid-Berechnungsfunktion, indem sie jeweils in reinem Python, optimiertem Numpy und einem hybriden Python-Mojo-Ansatz implementiert wurden.

Die Ergebnisse zeigen eine differenzierte Leistungslandschaft für loop-haarige Algorithmen, bei denen Daten vollständig mit nativen Mojo-Typen verarbeitet werden können. Mojo kann sowohl pure Python als auch hochoptimierten Numpy -Code erheblich übertreffen. Wir haben jedoch auch gesehen, dass Numpy für Aufgaben, die perfekt zu Numpys vektorisierten, vorkompilierten C-Funktionen übereinstimmen, einen leichten Rand über Mojo beibehalten können.

Diese Untersuchung zeigt, dass Mojo zwar ein leistungsstarkes neues Werkzeug für die Beschleunigung von Python ist, eine maximale Leistung zu erzielen, um einen nachdenklichen Ansatz zur Minimierung des Overheads „Bridge-Crossing“ zwischen den beiden Sprachlaufzeiten zu minimieren.

Wie immer, wenn Sie Leistungsverbesserungen in Ihrem Code, Take a look at, Take a look at, Take a look at in Betracht ziehen. Das ist der letzte Schiedsrichter, ob es sich lohnt oder nicht.

Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert