Mojo — ภาษาการเขียนโปรแกรมใหม่สำหรับนักพัฒนา นักวิทยาศาสตร์ AI/ML และวิศวกรซอฟต์แวร์ทุกคน
รายการโค้ด Mojo ที่ยอดเยี่ยม การแก้ปัญหา วิธีแก้ไข และไลบรารี เฟรมเวิร์ก ซอฟต์แวร์ และทรัพยากรในอนาคตที่คัดสรรมาอย่างดี
มารวบรวมความรู้ด้านเทคโนโลยีและแนวปฏิบัติที่ดีที่สุดใหม่ๆ ไว้ที่นี่
Mojo เป็นภาษาโปรแกรมที่ผสมผสานความเป็นมิตรต่อผู้ใช้ของ Python เข้ากับความสามารถด้านประสิทธิภาพของ C++ และ Rust นอกจากนี้ Mojo ยังช่วยให้ผู้ใช้ควบคุมระบบนิเวศอันกว้างขวางของไลบรารี Python
ในเวลาสั้นๆ
Mojo คือภาษาการเขียนโปรแกรมใหม่ที่เชื่อมช่องว่างระหว่างการวิจัยและการผลิตโดยการรวมไวยากรณ์ Python ที่ดีที่สุดเข้ากับการเขียนโปรแกรมระบบและการเขียนโปรแกรมเมตา
hello.mojo
หรือ hello.
นามสกุลไฟล์สามารถเป็นอิโมจิได้!
คุณสามารถอ่านเพิ่มเติมเกี่ยวกับสาเหตุที่ Modular ทำสิ่งนี้ได้ ทำไมต้อง Mojo
สิ่งที่เราต้องการคือโมเดลการเขียนโปรแกรมเชิงนวัตกรรมและปรับขนาดได้ ซึ่งสามารถกำหนดเป้าหมายไปที่ตัวเร่งความเร็วและระบบที่ต่างกันอื่นๆ ที่แพร่หลายในสาขา AI ... ระบบ AI ที่ประยุกต์จำเป็นต้องแก้ไขปัญหาเหล่านี้ทั้งหมด และเราตัดสินใจว่าไม่มีเหตุผลใดที่จะไม่สามารถทำได้ด้วยภาษาเดียว โมโจจึงถือกำเนิดขึ้น
แต่ Python ทำงานได้ดีมาก =)
เราไม่เห็นความจำเป็นที่จะต้องสร้างสรรค์สิ่งใหม่ๆ ในด้านไวยากรณ์ของภาษาหรือชุมชน ดังนั้นเราจึงเลือกที่จะยอมรับระบบนิเวศ Python เนื่องจากมีการใช้งานกันอย่างแพร่หลาย เป็นที่ชื่นชอบของระบบนิเวศ AI และเนื่องจากเราเชื่อว่ามันเป็นภาษาที่ดีจริงๆ
โมโจ แปลว่า "เสน่ห์วิเศษ" หรือ "พลังวิเศษ" เราคิดว่านี่เป็นชื่อที่เหมาะสมสำหรับภาษาที่นำพลังมหัศจรรย์มาสู่ Python :python: รวมถึงการปลดล็อกโมเดลการเขียนโปรแกรมที่เป็นนวัตกรรมสำหรับตัวเร่งความเร็วและระบบที่แตกต่างกันอื่น ๆ ที่แพร่หลายใน AI ในปัจจุบัน
Guido van Rossum เผด็จการที่มีเมตตาต่อชีวิตและ Christopher Arthur Lattner นักประดิษฐ์ผู้สร้างและผู้นำที่มีชื่อเสียงเกี่ยวกับ Mojopronunciation =)
ตามคำอธิบาย
ใครจะรู้ว่าภาษาโปรแกรมเหล่านี้จะมีความสุขมาก เพราะ Mojo ได้ประโยชน์จากบทเรียนมากมายที่เรียนรู้จากภาษาอื่นอย่าง Rust, Swift, Julia, Zig, Nim ฯลฯ
[ใหม่]
ตอนนี้ Github ตรวจจับรหัส Mojo โดยอัตโนมัติ!
กรอบงาน HTTP ที่ง่ายและรวดเร็วสำหรับ Mojo! เหมาะสำหรับการสร้างบริการบนเว็บและ API แบบง่ายๆ สำหรับชาวโมจิเชียน
กรอบการเปรียบเทียบการใช้งาน LLama
การแปลโค้ด Python เป็น Mojo อัตโนมัติ
การวิจัยฐานข้อมูลภาษาการเขียนโปรแกรม
19 ตุลาคม 2023 Mojo พร้อมใช้งานบน Mac แล้ว! ใช้คอนโซลนักพัฒนาซอฟต์แวร์
Chris Lattner: อนาคตของการเขียนโปรแกรมและ AI | ไฟแนนเชี่ยล Fridman พอดคาสต์ #381
อธิบายระบบประเภท Mojo และ Python | คริส แลตต์เนอร์ และเล็กซ์ ฟรีดแมน
Mojo สามารถรันโค้ด Python ได้หรือไม่? - คริส แลตต์เนอร์ และเล็กซ์ ฟรีดแมน
การเปลี่ยนจากภาษาโปรแกรม Python เป็นภาษาโปรแกรม Mojo | คริส แลตต์เนอร์ และเล็กซ์ ฟรีดแมน
หัวข้อ GitHub ใหม่ mojo-lang ดังนั้นคุณสามารถปฏิบัติตามได้
Guido van Rossum เกี่ยวกับ Mojo = Python พร้อมประสิทธิภาพ C++/GPU หรือไม่
โครงสร้างเทนเซอร์พร้อมปฏิบัติการพื้นฐาน #251
เมทริกซ์ fn ด้วยตัวเลข #267
อัปเดตเกี่ยวกับ lambda
และการปิด parameter
และฟังก์ชันลำดับที่สูงขึ้นใน mojo #244
25 พฤษภาคม 2023 Guido van Rossum (gvanrossum#8415) ผู้สร้างและกิตติคุณ BDFL ของ Python เยี่ยมชม Discord Chat สาธารณะของ Mojo
กำลังรอการเน้นไวยากรณ์ Mojo ที่ GitHub
ใหม่ Mojorelease 2023-05-24
[เก่า]
โมโจ
brew install hyperfine
brew install macchina
pip3 install numpy matplotlib scipy
brew install silicon
เวอร์ชัน Python / Mojo / Codon / Rust
> python3 --version
Python 3.11.6
> mojo --version
mojo 0.4.0 (9e33b013)
> codon --version
0.16.3
> rustc --version
rustc 1.65.0-nightly (9243168fa 2022-08-31)
ให้เราค้นหาลำดับฟีโบนัชชีที่ไหน
ยังไม่มีข้อความ = 100
def fibonacci_recursion ( n ):
return n if n < 2 else fibonacci_recursion ( n - 1 ) + fibonacci_recursion ( n - 2 )
fibonacci_recursion ( 100 )
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json python_recursion.json ' python3 benchmarks/fibonacci_sequence/python_recursion.py '
ผลลัพธ์: หมดเวลา ฉันยกเลิกการคำนวณหลังจากผ่านไป 1 นาที
def fibonacci_iteration ( n ):
a , b = 0 , 1
for _ in range ( n ):
a , b = b , a + b
return a
fibonacci_iteration ( 100 )
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/python_iteration.json ' python3 benchmarks/fibonacci_sequence/python_iteration.py '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: เกณฑ์มาตรฐาน python3/fibonacci_sequence/python_iteration.py
เวลา (เฉลี่ย ± σ): 16374.7 µs ± 904.0 µs [ผู้ใช้: 11483.5 µs, ระบบ: 3680.0 µs]
ช่วง (ต่ำสุด … สูงสุด): 15361.0 µs … 22863.3 µs 100 รอบ
python3 -m compileall benchmarks/fibonacci_sequence/python_recursion.py
python3 -m compileall benchmarks/fibonacci_sequence/python_iteration.py
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/python_recursion.cpython-311.json ' python3 benchmarks/fibonacci_sequence/__pycache__/python_recursion.cpython-311.pyc '
# TIMEOUT!
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/python_iteration.cpython-311.json ' python3 benchmarks/fibonacci_sequence/__pycache__/python_iteration.cpython-311.pyc '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: เกณฑ์มาตรฐาน python3/fibonacci_sequence/ pycache /python_iteration.cpython-311.pyc
เวลา (เฉลี่ย ± σ): 16584.6 µs ± 761.5 µs [ผู้ใช้: 11451.8 µs, ระบบ: 3813.3 µs]
ช่วง (ต่ำสุด … สูงสุด): 15592.0 µs … 20953.2 µs 100 รอบ
fn fibonacci_recursion ( n : Int) -> Int:
return n if n < 2 else fibonacci_recursion(n - 1 ) + fibonacci_recursion(n - 2 )
fn main ():
_ = fibonacci_recursion( 100 )
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/mojo_recursion.json ' mojo run benchmarks/fibonacci_sequence/mojo_recursion.mojo '
ผลลัพธ์: หมดเวลา ฉันยกเลิกการคำนวณหลังจากผ่านไป 1 นาที
fn fibonacci_iteration ( n : Int) -> Int:
var a : Int = 0
var b : Int = 1
for _ in range (n):
a = b
b = a + b
return a
fn main ():
_ = fibonacci_iteration( 100 )
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/mojo_iteration.json ' mojo run benchmarks/fibonacci_sequence/mojo_iteration.mojo '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: mojo เรียกใช้การวัดประสิทธิภาพ/fibonacci_sequence/mojo_iteration.mojo
เวลา (เฉลี่ย ± σ): 43852.7 µs ± 1353.5 µs [ผู้ใช้: 38156.0 µs, ระบบ: 10407.3 µs]
ช่วง (ต่ำสุด … สูงสุด): 42033.6 µs … 49357.3 µs 100 รอบ
mojo build benchmarks/fibonacci_sequence/mojo_recursion.mojo
mojo build benchmarks/fibonacci_sequence/mojo_iteration.mojo
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/mojo_recursion.exe.json ' ./benchmarks/fibonacci_sequence/mojo_recursion '
# TIMEOUT!
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/mojo_iteration.exe.json ' ./benchmarks/fibonacci_sequence/mojo_iteration '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: ./benchmarks/fibonacci_sequence/mojo_iteration
เวลา (เฉลี่ย ± σ): 934.6 µs ± 468.9 µs [ผู้ใช้: 409.8 µs, ระบบ: 247.8 µs]
ช่วง (ต่ำสุด…สูงสุด): 552.7 µs … 4522.9 µs 100 รอบ
def fibonacci_recursion(n):
return n if n < 2 else fibonacci_recursion(n - 1) + fibonacci_recursion(n - 2)
fibonacci_recursion(100)
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/codon_recursion.json ' codon run --release benchmarks/fibonacci_sequence/codon_recursion.codon '
ผลลัพธ์: หมดเวลา ฉันยกเลิกการคำนวณหลังจากผ่านไป 1 นาที
def fibonacci_iteration(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a+b
return a
fibonacci_iteration(100)
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/codon_iteration.json ' codon run --release benchmarks/fibonacci_sequence/codon_iteration.codon '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: การรันโค้ด --release การวัดประสิทธิภาพ/fibonacci_sequence/codon_iteration.codon
เวลา (เฉลี่ย ± σ): 628060.1 µs ± 10430.5 µs [ผู้ใช้: 584524.3 µs, ระบบ: 39358.5 µs]
ช่วง (ต่ำสุด … สูงสุด): 612742.5 µs … 662716.9 µs 100 รอบ
codon build --release -exe benchmarks/fibonacci_sequence/codon_recursion.codon
codon build --release -exe benchmarks/fibonacci_sequence/codon_iteration.codon
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json codon_recursion.exe.json ' ./benchmarks/fibonacci_sequence/codon_recursion '
# TIMEOUT!
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/codon_iteration.exe.json ' ./benchmarks/fibonacci_sequence/codon_iteration '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: ./benchmarks/fibonacci_sequence/codon_iteration
เวลา (เฉลี่ย ± σ): 2732.7 µs ± 1145.5 µs [ผู้ใช้: 1466.0 µs, ระบบ: 1061.5 µs]
ช่วง (ต่ำสุด … สูงสุด): 2036.6 µs … 13236.3 µs 100 รอบ
fn fibonacci_recursive ( n : i64 ) -> i64 {
if n < 2 {
return n ;
}
return fibonacci_recursive ( n - 1 ) + fibonacci_recursive ( n - 2 ) ;
}
fn main ( ) {
let _ = fibonacci_recursive ( 100 ) ;
}
rustc -C opt-level=3 benchmarks/fibonacci_sequence/rust_recursion.rs -o benchmarks/fibonacci_sequence/rust_recursion
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/rust_recursion.json ' ./benchmarks/fibonacci_sequence/rust_recursion '
ผลลัพธ์: หมดเวลา ฉันยกเลิกการคำนวณหลังจากผ่านไป 1 นาที
fn fibonacci_iteration ( n : usize ) -> usize {
let mut a = 1 ;
let mut b = 1 ;
for _ in 1 ..n {
let old = a ;
a = b ;
b += old ;
}
b
}
fn main ( ) {
let _ = fibonacci_iteration ( 100 ) ;
}
rustc -C opt-level=3 benchmarks/fibonacci_sequence/rust_iteration.rs -o benchmarks/fibonacci_sequence/rust_iteration
hyperfine --warmup 10 -r 100 --time-unit=microsecond --export-json benchmarks/fibonacci_sequence/rust_iteration.json ' ./benchmarks/fibonacci_sequence/rust_iteration '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: ./benchmarks/fibonacci_sequence/rust_iteration
เวลา (เฉลี่ย ± σ): 848.9 µs ± 283.2 µs [ผู้ใช้: 371.8 µs, ระบบ: 261.4 µs]
ช่วง (ต่ำสุด…สูงสุด): 525.9 µs … 2607.3 µs 100 รอบ
# Merge all JSON files into benchmarks.json
python3 benchmarks/hyperfine-scripts/merge_jsons.py benchmarks/fibonacci_sequence/ benchmarks/fibonacci_sequence/benchmarks.json
python3 benchmarks/hyperfine-scripts/plot2.py benchmarks/fibonacci_sequence/benchmarks.json
python3 benchmarks/hyperfine-scripts/plot3.py benchmarks/fibonacci_sequence/benchmarks.json
python3 benchmarks/hyperfine-scripts/advanced_statistics.py benchmarks/fibonacci_sequence/benchmarks.json > benchmarks/fibonacci_sequence/benchmarks.json.md
silicon benchmarks/fibonacci_sequence/benchmarks.json.md -l python -o benchmarks/fibonacci_sequence/benchmarks.json.md.png
สถิติขั้นสูง
ทั้งหมดเข้าด้วยกัน
ซูมแล้ว
อย่างละเอียดทีละรายการ
สถานที่
แต่มีคำถามมากมาย:
mojo run
ช้ามาก?codon run --release
ช้ามาก?run
ดังนั้นเราจึงบอกได้ว่า Mojo นั้นเร็วเท่ากับ Rust บน Mac!
มาตามหา Mandelbrot Set กันดีกว่า
ความกว้าง = 960
ความสูง = 960
MAX_ITERS = 200
MIN_X = -2.0
MAX_X = 0.6
MIN_Y = -1.5
MAX_Y = 1.5
def mandelbrot_kernel ( c ):
z = c
for i in range ( MAX_ITERS ):
z = z * z + c # Change this for different Multibrot sets (e.g., 2 for Mandelbrot)
if z . real * z . real + z . imag * z . imag > 4 :
return i
return MAX_ITERS
def compute_mandelbrot ():
t = [[ 0 for _ in range ( WIDTH )] for _ in range ( HEIGHT )] # Pixel matrix
dx = ( MAX_X - MIN_X ) / WIDTH
dy = ( MAX_Y - MIN_Y ) / HEIGHT
for row in range ( HEIGHT ):
for col in range ( WIDTH ):
t [ row ][ col ] = mandelbrot_kernel ( complex ( MIN_X + col * dx , MIN_Y + row * dy ))
return t
compute_mandelbrot ()
python3 -m compileall benchmarks/multibrot_set/multibrot.py
hyperfine --warmup 10 -r 10 --time-unit=microsecond --export-json benchmarks/multibrot_set/multibrot.cpython-311.json ' python3 benchmarks/multibrot_set/__pycache__/multibrot.cpython-311.pyc '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: เกณฑ์มาตรฐาน python3/multibrot_set/ pycache /multibrot.cpython-311.pyc
เวลา (เฉลี่ย ± σ): 5444155.4 µs ± 23059.7 µs [ผู้ใช้: 5419790.1 µs, ระบบ: 18131.3 µs]
ช่วง (ต่ำสุด … สูงสุด): 5408155.3 µs … 5490548.4 µs 10 รอบ
เวอร์ชัน Mojo ที่ไม่มีการเพิ่มประสิทธิภาพ
# Compute the number of steps to escape.
def multibrot_kernel ( c : ComplexFloat64) -> Int:
z = c
for i in range ( MAX_ITERS ):
z = z * z + c # Change this for different Multibrot sets (e.g., 2 for Mandelbrot)
if z.squared_norm() > 4 :
return i
return MAX_ITERS
def compute_multibrot () -> Tensor[FloatType]:
# create a matrix. Each element of the matrix corresponds to a pixel
t = Tensor[FloatType]( HEIGHT , WIDTH )
dx = ( MAX_X - MIN_X ) / WIDTH
dy = ( MAX_Y - MIN_Y ) / HEIGHT
y = MIN_Y
for row in range ( HEIGHT ):
x = MIN_X
for col in range ( WIDTH ):
t[Index(row, col)] = multibrot_kernel(ComplexFloat64(x, y))
x += dx
y += dy
return t
_ = compute_multibrot()
mojo build benchmarks/multibrot_set/multibrot.mojo
hyperfine --warmup 10 -r 10 --time-unit=microsecond --export-json benchmarks/multibrot_set/multibrot.exe.json ' ./benchmarks/multibrot_set/multibrot '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: ./benchmarks/multibrot_set/multibrot
เวลา (เฉลี่ย ± σ): 135880.5 µs ± 1175.4 µs [ผู้ใช้: 133309.3 µs, ระบบ: 1700.1 µs]
ช่วง (ต่ำสุด … สูงสุด): 134639.9 µs … 137621.4 µs 10 รอบ
fn mandelbrot_kernel_SIMD [
simd_width : Int
]( c : ComplexSIMD[float_type, simd_width]) -> SIMD [float_type, simd_width]:
""" A vectorized implementation of the inner mandelbrot computation. """
let cx = c.re
let cy = c.im
var x = SIMD [float_type, simd_width]( 0 )
var y = SIMD [float_type, simd_width]( 0 )
var y2 = SIMD [float_type, simd_width]( 0 )
var iters = SIMD [float_type, simd_width]( 0 )
var t : SIMD [DType.bool, simd_width] = True
for i in range ( MAX_ITERS ):
if not t.reduce_or():
break
y2 = y * y
y = x.fma(y + y, cy)
t = x.fma(x, y2) <= 4
x = x.fma(x, cx - y2)
iters = t.select(iters + 1 , iters)
return iters
fn compute_multibrot_parallelized () -> Tensor[float_type]:
let t = Tensor[float_type](height, width)
@parameter
fn worker ( row : Int):
let scale_x = (max_x - min_x) / width
let scale_y = (max_y - min_y) / height
@parameter
fn compute_vector [ simd_width : Int]( col : Int):
""" Each time we operate on a `simd_width` vector of pixels. """
let cx = min_x + (col + iota[float_type, simd_width]()) * scale_x
let cy = min_y + row * scale_y
let c = ComplexSIMD[float_type, simd_width](cx, cy)
t.data().simd_store[simd_width](
row * width + col, mandelbrot_kernel_SIMD[simd_width](c)
)
# Vectorize the call to compute_vector where call gets a chunk of pixels.
vectorize[simd_width, compute_vector](width)
# Parallelized
parallelize[worker](height, height)
return t
def main ():
_ = compute_multibrot_parallelized()
mojo build benchmarks/multibrot_set/multibrot_mojo_parallelize.mojo
hyperfine --warmup 10 -r 10 --time-unit=microsecond --export-json benchmarks/multibrot_set/multibrot_mojo_parallelize.exe.json ' ./benchmarks/multibrot_set/multibrot_mojo_parallelize '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: ./benchmarks/multibrot_set/multibrot_mojo_parallelize
เวลา (เฉลี่ย ± σ): 7139.4 µs ± 596.4 µs [ผู้ใช้: 36535.2 µs, ระบบ: 6670.1 µs]
ช่วง (ต่ำสุด…สูงสุด): 6222.6 µs … 8269.7 µs 10 รอบ
def mandelbrot_kernel(c):
z = c
for i in range(MAX_ITERS):
z = z * z + c # Change this for different Multibrot sets (e.g., 2 for Mandelbrot)
if z.real * z.real + z.imag * z.imag > 4:
return i
return MAX_ITERS
def compute_mandelbrot():
t = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)] # Pixel matrix
dx = (MAX_X - MIN_X) / WIDTH
dy = (MAX_Y - MIN_Y) / HEIGHT
@par(collapse=2)
for row in range(HEIGHT):
for col in range(WIDTH):
t[row][col] = mandelbrot_kernel(complex(MIN_X + col * dx, MIN_Y + row * dy))
return t
compute_mandelbrot()
สำหรับการทดสอบการทำงานหรือการลงจุด (โค้ดที่ไม่มีเครื่องหมายข้อคิดเห็นในไฟล์)
CODON_PYTHON=/opt/homebrew/opt/[email protected]/Frameworks/Python.framework/Versions/3.11/lib/libpython3.11.dylib codon run --release benchmarks/multibrot_set/multibrot.codon
สร้างและดำเนินการ
codon build --release -exe benchmarks/multibrot_set/multibrot.codon -o benchmarks/multibrot_set/multibrot_codon
hyperfine --warmup 10 -r 10 --time-unit=microsecond --export-json benchmarks/multibrot_set/multibrot_codon.json ' ./benchmarks/multibrot_set/multibrot_codon '
ผลลัพธ์ :
เกณฑ์มาตรฐาน 1: ./benchmarks/multibrot_set/multibrot_codon
เวลา (เฉลี่ย ± σ): 44184.7 µs ± 1142.0 µs [ผู้ใช้: 248773.9 µs, ระบบ: 72935.3 µs]
ช่วง (ต่ำสุด … สูงสุด): 42963.8 µs … 46456.2 µs 10 รอบ
codon build --release -exe benchmarks/multibrot_set/multibrot_codon_par.codon -o benchmarks/multibrot_set/multibrot_codon_par
hyperfine --warmup 10 -r 10 --time-unit=microsecond --export-json benchmarks/multibrot_set/multibrot_codon_par.json ' ./benchmarks/multibrot_set/multibrot_codon_par '
# Merge all JSON files into benchmarks.json
python3 benchmarks/hyperfine-scripts/merge_jsons.py benchmarks/multibrot_set/ benchmarks/multibrot_set/benchmarks.json
python3 benchmarks/hyperfine-scripts/plot2.py benchmarks/multibrot_set/benchmarks.json
python3 benchmarks/hyperfine-scripts/plot3.py benchmarks/multibrot_set/benchmarks.json
python3 benchmarks/hyperfine-scripts/advanced_statistics.py benchmarks/multibrot_set/benchmarks.json > benchmarks/multibrot_set/benchmarks.json.md
silicon benchmarks/multibrot_set/benchmarks.json.md -l python -o benchmarks/multibrot_set/benchmarks.json.md.png
สถิติขั้นสูง
ทั้งหมดเข้าด้วยกัน
ซูมแล้ว
อย่างละเอียดทีละรายการ
สถานที่
ลิงค์:
Mandelbrot = Multibrot ที่มี power = 2
z = z ** power + c # You can change this for different set
หมอนในตัว ImagingEffectMandelbrot
Mandelbrot เวอร์ชัน Exaloop Codon
Mandelbrot เวอร์ชันโมดูลาร์ Mojo
โมโจคอมเพล็กซ์กำลังสอง_norm
มัตพล็อตลิบ มานเดลโบรต์
ในวิทยาการคอมพิวเตอร์ อัลกอริธึมการค้นหาแบบไบนารีหรือที่เรียกว่าการค้นหาแบบครึ่งช่วง การค้นหาแบบลอการิทึม หรือแบบไบนารีสับ เป็นอัลกอริทึมการค้นหาที่ค้นหาตำแหน่งของค่าเป้าหมายภายในอาร์เรย์ที่เรียงลำดับ
มาเขียนโค้ดกับ Python, Mojo, Swift, V, Julia, Nim, Zig กันดีกว่า
หมายเหตุ: สำหรับเวอร์ชัน Python และ Mojo ฉันคงการปรับให้เหมาะสมไว้บางส่วนและทำให้โค้ดคล้ายกันสำหรับการวัดและการเปรียบเทียบ
from typing import List
import timeit
SIZE = 1000000
MAX_ITERS = 100
COLLECTION = tuple ( i for i in range ( SIZE )) # Make it aka at compile-time.
def python_binary_search ( element : int , array : List [ int ]) -> int :
start = 0
stop = len ( array ) - 1
while start <= stop :
index = ( start + stop ) // 2
pivot = array [ index ]
if pivot == element :
return index
elif pivot > element :
stop = index - 1
elif pivot < element :
start = index + 1
return - 1
def test_python_binary_search ():
_ = python_binary_search ( SIZE - 1 , COLLECTION )
print (
"Average execution time of func in sec" ,
timeit . timeit ( lambda : test_python_binary_search (), number = MAX_ITERS ),
)
"""Implements basic binary search."""
from Benchmark import Benchmark
from Vector import DynamicVector
alias SIZE = 1000000
alias NUM_WARMUP = 0
alias MAX_ITERS = 100
fn mojo_binary_search ( element : Int , array : DynamicVector [ Int ]) - > Int :
var start = 0
var stop = len ( array ) - 1
while start <= stop :
let index = ( start + stop ) // 2
let pivot = array [ index ]
if pivot == element :
return index
elif pivot > element :
stop = index - 1
elif pivot < element :
start = index + 1
return - 1
@ parameter # statement runs at compile-time.
fn get_collection () - > DynamicVector [ Int ]:
var v = DynamicVector [ Int ]( SIZE )
for i in range ( SIZE ):
v . push_back ( i )
return v
fn test_mojo_binary_search () - > F64 :
fn test_closure ():
_ = mojo_binary_search ( SIZE - 1 , get_collection ())
return F64 ( Benchmark ( NUM_WARMUP , MAX_ITERS ). run [ test_closure ]()) / 1e9
print (
"Average execution time of func in sec " ,
test_mojo_binary_search (),
)
เป็นการค้นหาแบบไบนารีแรกที่เขียนในชุมชน Mojoby (@ego) และโพสต์ใน mojo-chat
func binarySearch ( items : [ Int ] , elem : Int ) -> Int {
var low = 0
var high = items . count - 1
var mid = 0
while low <= high {
mid = Int ( ( high + low ) / 2 )
if items [ mid ] < elem {
low = mid + 1
} else if items [ mid ] > elem {
high = mid - 1
} else {
return mid
}
}
return - 1
}
let items = [ 1 , 2 , 3 , 4 , 0 ] . sorted ( )
let res = binarySearch ( items : items , elem : 4 )
print ( res )
function binarysearch (lst :: Vector{T} , val :: T ) where T
low = 1
high = length (lst)
while low ≤ high
mid = (low + high) ÷ 2
if lst[mid] > val
high = mid - 1
elseif lst[mid] < val
low = mid + 1
else
return mid
end
end
return 0
end
proc binarySearch [T](a: openArray [T], key: T): int =
var b = len (a)
while result < b:
var mid = ( result + b) div 2
if a[mid] < key: result = mid + 1
else : b = mid
if result >= len (a) or a[ result ] != key: result = - 1
let res = @ [ 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 12 , 14 , 16 , 18 , 20 , 22 , 25 , 27 , 30 ]
echo binarySearch (res, 10 )
const std = @import ( "std" );
fn binarySearch ( comptime T : type , arr : [] const T , target : T ) ? usize {
var lo : usize = 0 ;
var hi : usize = arr . len - 1 ;
while ( lo <= hi ) {
var mid : usize = ( lo + hi ) / 2 ;
if ( arr [ mid ] == target ) {
return mid ;
} else if ( arr [ mid ] < target ) {
lo = mid + 1 ;
} else {
hi = mid - 1 ;
}
}
return null ;
}
fn binary_search (a [] int , value int ) int {
mut low := 0
mut high := a.len - 1
for low < = high {
mid := (low + high) / 2
if a[mid] > value {
high = mid - 1
} else if a[mid] < value {
low = mid + 1
} else {
return mid
}
}
return - 1
}
fn main () {
search_list := [ 1 , 2 , 3 , 5 , 6 , 7 , 8 , 9 , 10 ]
println ( binary_search (search_list, 9 ))
}
fn breadth_first_search_path (graph map [ string ][] string , vertex string , target string ) [] string {
mut path := [] string {}
mut visited := [] string {init: vertex}
mut queue := [][][] string {}
queue << [[vertex], path]
for queue.len > 0 {
mut idx := queue.len - 1
node := queue[idx][ 0 ][ 0 ]
path = queue[idx][ 1 ]
queue. delete (idx)
if node == target {
path << node
return path
}
for child in graph[node] {
mut tmp := path. clone ()
if child ! in visited {
visited << child
tmp << node
queue << [[child], tmp]
}
}
}
return path
}
fn main () {
graph := map {
'A' : [ 'B' , 'C' ]
'B' : [ 'A' , 'D' , 'E' ]
'C' : [ 'A' , 'F' ]
'D' : [ 'B' ]
'E' : [ 'B' , 'F' ]
'F' : [ 'C' , 'E' ]
}
println ( 'Graph: $graph ' )
path := breadth_first_search_path (graph, 'A' , 'F' )
println ( 'The shortest path from node A to node F is: $path ' )
assert path == [ 'A' , 'C' , 'F' ]
}
import timeit
SIZE = 100
MAX_ITERS = 100
def _fizz_buzz (): # Make it aka at compile-time.
res = []
for n in range ( 1 , SIZE + 1 ):
if ( n % 3 == 0 ) and ( n % 5 == 0 ):
s = "FizzBuzz"
elif n % 3 == 0 :
s = "Fizz"
elif n % 5 == 0 :
s = "Buzz"
else :
s = str ( n )
res . append ( s )
return res
DATA = _fizz_buzz ()
def fizz_buzz ():
print ( " n " . join ( DATA ))
print (
"Average execution time of Python func in sec" ,
timeit . timeit ( lambda : fizz_buzz (), number = MAX_ITERS ),
)
# Average execution time of Python func in sec 0.005334990004485007
( import '[java.io OutputStream])
( require '[clojure.java.io :as io])
( def devnull ( io/writer ( OutputStream/nullOutputStream )))
( defmacro timeit [n expr]
`(with-out-str ( time
( dotimes [_# ~( Math/pow 1 n)]
( binding [*out* devnull]
~expr)))))
( defmacro macro-fizz-buzz [n]
`( fn []
( print
~( apply str
( for [i ( range 1 ( inc n))]
( cond
( zero? ( mod i 15 )) " FizzBuzz n "
( zero? ( mod i 5 )) " Buzz n "
( zero? ( mod i 3 )) " Fizz n "
:else ( str i " n " )))))))
( print ( timeit 100 ( macro-fizz-buzz 100 )))
; ; "Elapsed time: 0.175486 msecs"
; ; Average execution time of Clojure func in sec 0.000175486 seconds
from String import String
from Benchmark import Benchmark
alias SIZE = 100
alias NUM_WARMUP = 0
alias MAX_ITERS = 100
@ parameter # statement runs at compile-time.
fn _fizz_buzz () - > String :
var res : String = ""
for n in range ( 1 , SIZE + 1 ):
if ( n % 3 == 0 ) and ( n % 5 == 0 ):
res += "FizzBuzz"
elif n % 3 == 0 :
res += "Fizz"
elif n % 5 == 0 :
res += "Buzz"
else :
res += String ( n )
res += " n "
return res
fn fizz_buzz ():
print ( _fizz_buzz ())
fn run_benchmark () - > F64 :
fn _closure ():
_ = fizz_buzz ()
return F64 ( Benchmark ( NUM_WARMUP , MAX_ITERS ). run [ _closure ]()) / 1e9
print (
"Average execution time of func in sec " ,
run_benchmark (),
)
# Average execution time of func in sec 0.000104
นี่เป็น Fizz buzz แรกที่เขียนด้วยภาษา Mojo โดยชุมชน (@Ego)
เราจะใช้อัลกอริทึมจากการอ้างอิงที่รู้จักสำหรับหนังสืออัลกอริทึม Introduction to Algorithms A3
ชื่อเสียงของมันนำไปสู่การใช้คำย่อทั่วไป " CLRS " (Cormen, Leiserson, Rivest, Stein) หรือในฉบับพิมพ์ครั้งแรก " CLR " (Cormen, Leiserson, Rivest)
บทที่ 2 "2.3.1 แนวทางแบ่งแยกและพิชิต"
% % python
import timeit
MAX_ITERS = 100
def merge ( A , p , q , r ):
n1 = q - p + 1
n2 = r - q
L = [ None ] * n1
R = [ None ] * n2
for i in range ( n1 ):
L [ i ] = A [ p + i ]
for j in range ( n2 ):
R [ j ] = A [ q + 1 + j ]
i = 0
j = 0
k = p
while i < n1 and j < n2 :
if L [ i ] <= R [ j ]:
A [ k ] = L [ i ]
i += 1
else :
A [ k ] = R [ j ]
j += 1
k += 1
while i < n1 :
A [ k ] = L [ i ]
i += 1
k += 1
while j < n2 :
A [ k ] = R [ j ]
j += 1
k += 1
def merge_sort ( A , p , r ):
if p < r :
q = ( p + r ) // 2
merge_sort ( A , p , q )
merge_sort ( A , q + 1 , r )
merge ( A , p , q , r )
def run_benchmark_merge_sort ():
A = [ 14 , 72 , 50 , 83 , 18 , 20 , 13 , 30 , 17 , 87 , 94 , 65 , 24 , 99 , 70 , 44 , 5 , 12 , 74 , 6 , 32 , 63 , 91 , 88 , 43 , 54 , 27 , 39 , 64 , 78 , 29 , 62 , 58 , 59 , 61 , 89 , 2 , 15 , 41 , 9 , 93 , 90 , 23 , 96 , 73 , 14 , 8 , 28 , 11 , 42 , 77 , 34 , 52 , 80 , 57 , 84 , 21 , 60 , 66 , 40 , 7 , 85 , 47 , 98 , 97 , 35 , 82 , 36 , 49 , 3 , 68 , 22 , 67 , 81 , 56 , 71 , 4 , 38 , 69 , 95 , 16 , 48 , 1 , 31 , 75 , 19 , 10 , 25 , 79 , 45 , 76 , 33 , 53 , 55 , 46 , 37 , 26 , 51 , 92 , 86 ]
merge_sort ( A , 0 , len ( A ) - 1 )
print (
"Average execution time of Python `merge_sort` in sec" ,
timeit . timeit ( lambda : run_benchmark_merge_sort (), number = MAX_ITERS ),
)
# Average execution time of Python `merge_sort` in sec 0.019136679999064654
def run_benchmark_sort ():
A = [ 14 , 72 , 50 , 83 , 18 , 20 , 13 , 30 , 17 , 87 , 94 , 65 , 24 , 99 , 70 , 44 , 5 , 12 , 74 , 6 , 32 , 63 , 91 , 88 , 43 , 54 , 27 , 39 , 64 , 78 , 29 , 62 , 58 , 59 , 61 , 89 , 2 , 15 , 41 , 9 , 93 , 90 , 23 , 96 , 73 , 14 , 8 , 28 , 11 , 42 , 77 , 34 , 52 , 80 , 57 , 84 , 21 , 60 , 66 , 40 , 7 , 85 , 47 , 98 , 97 , 35 , 82 , 36 , 49 , 3 , 68 , 22 , 67 , 81 , 56 , 71 , 4 , 38 , 69 , 95 , 16 , 48 , 1 , 31 , 75 , 19 , 10 , 25 , 79 , 45 , 76 , 33 , 53 , 55 , 46 , 37 , 26 , 51 , 92 , 86 ]
A . sort ()
print (
"Average execution time of Python builtin `sort` in sec" ,
timeit . timeit ( lambda : run_benchmark_sort (), number = MAX_ITERS ),
)
# Average execution time of Python builtin `sort` in sec 0.00019922800129279494
from Benchmark import Benchmark
from Vector import DynamicVector
from StaticTuple import StaticTuple
from Sort import sort
alias NUM_WARMUP = 0
alias MAX_ITERS = 100
fn merge ( inout A : DynamicVector [ Int ], p : Int , q : Int , r : Int ):
let n1 = q - p + 1
let n2 = r - q
var L = DynamicVector [ Int ]( n1 )
var R = DynamicVector [ Int ]( n2 )
for i in range ( n1 ):
L [ i ] = A [ p + i ]
for j in range ( n2 ):
R [ j ] = A [ q + 1 + j ]
var i = 0
var j = 0
var k = p
while i < n1 and j < n2 :
if L [ i ] <= R [ j ]:
A [ k ] = L [ i ]
i += 1
else :
A [ k ] = R [ j ]
j += 1
k += 1
while i < n1 :
A [ k ] = L [ i ]
i += 1
k += 1
while j < n2 :
A [ k ] = R [ j ]
j += 1
k += 1
fn merge_sort ( inout A : DynamicVector [ Int ], p : Int , r : Int ):
if p < r :
let q = ( p + r ) // 2
merge_sort ( A , p , q )
merge_sort ( A , q + 1 , r )
merge ( A , p , q , r )
@ parameter
fn create_vertor () - > DynamicVector [ Int ]:
let st = StaticTuple [ MAX_ITERS , Int ]( 14 , 72 , 50 , 83 , 18 , 20 , 13 , 30 , 17 , 87 , 94 , 65 , 24 , 99 , 70 , 44 , 5 , 12 , 74 , 6 , 32 , 63 , 91 , 88 , 43 , 54 , 27 , 39 , 64 , 78 , 29 , 62 , 58 , 59 , 61 , 89 , 2 , 15 , 41 , 9 , 93 , 90 , 23 , 96 , 73 , 14 , 8 , 28 , 11 , 42 , 77 , 34 , 52 , 80 , 57 , 84 , 21 , 60 , 66 , 40 , 7 , 85 , 47 , 98 , 97 , 35 , 82 , 36 , 49 , 3 , 68 , 22 , 67 , 81 , 56 , 71 , 4 , 38 , 69 , 95 , 16 , 48 , 1 , 31 , 75 , 19 , 10 , 25 , 79 , 45 , 76 , 33 , 53 , 55 , 46 , 37 , 26 , 51 , 92 , 86 )
var v = DynamicVector [ Int ]( st . __len__ ())
for i in range ( st . __len__ ()):
v . push_back ( st [ i ])
return v
fn run_benchmark_merge_sort () - > F64 :
fn _closure ():
var A = create_vertor ()
merge_sort ( A , 0 , len ( A ) - 1 )
return F64 ( Benchmark ( NUM_WARMUP , MAX_ITERS ). run [ _closure ]()) / 1e9
print (
"Average execution time of Mojo `merge_sort` in sec " ,
run_benchmark_merge_sort (),
)
# Average execution time of Mojo `merge_sort` in sec 1.1345999999999999e-05
fn run_benchmark_sort () - > F64 :
fn _closure ():
var A = create_vertor ()
sort ( A )
return F64 ( Benchmark ( NUM_WARMUP , MAX_ITERS ). run [ _closure ]()) / 1e9
print (
"Average execution time of Mojo builtin `sort` in sec " ,
run_benchmark_sort (),
)
# Average execution time of Mojo builtin `sort` in sec 2.988e-06
คุณสามารถใช้มันได้เช่น:
# Usage: merge_sort
var A = create_vertor ()
merge_sort ( A , 0 , len ( A ) - 1 )
print ( len ( A ))
print ( A [ 0 ], A [ 99 ])
Builtin from Sort import sort
Quicksort เร็วกว่าการใช้งานของเราเล็กน้อย แต่เราสามารถปรับให้เหมาะสมได้ในภาษาเชิงลึกและตามปกติด้วยอัลกอริธึม =) และกระบวนทัศน์การเขียนโปรแกรม
หรั่ง | วินาที |
---|---|
Python merge_sort | 0.019136679 |
การเรียงลำดับ Python ในตัว | 0.000199228 |
โมโจ merge_sort | 0.000011346 |
Mojo ในตัวเรียงลำดับ | 0.000002988 |
เรามาสร้างพล็อตสำหรับตารางนี้กันดีกว่า
#%%python
import matplotlib . pyplot as plt
import numpy as np
languages = [ 'Python merge_sort' , 'Python builtin sort' , 'Mojo merge_sort' , 'Mojo builtin sort' ]
seconds = [ 0.019136679 , 0.000199228 , 0.000011346 , 0.000002988 ]
# Apply a custom transformation to the values
transformed_seconds = [ np . sqrt ( 1 / x ) for x in seconds ]
plt . barh ( languages , transformed_seconds )
plt . xlabel ( 'Custom Transformation' )
plt . ylabel ( 'Language and Sort Type' )
plt . title ( 'Comparison of Sorting Algorithms (Custom Transformation)' )
plt . show ()
บันทึกย่อ ยิ่งมากก็ยิ่งดีและเร็วขึ้น
ฉันขอแนะนำอย่างยิ่งให้เริ่มจากที่นี่ HelloMojo และทำความเข้าใจการกำหนด พารามิเตอร์ [พารามิเตอร์] และ [นิพจน์พารามิเตอร์] ที่นี่ เช่นเดียวกับในตัวอย่างนี้:
fn concat [ len1 : Int , len2 : Int ]( lhs : MySIMD [ len1 ], rhs : MySIMD [ len2 ]) - > MySIMD [ len1 + len2 ]:
let result = MySIMD [ len1 + len2 ]()
for i in range ( len1 ):
result [ i ] = lhs [ i ]
for j in range ( len2 ):
result [ len1 + j ] = rhs [ j ]
return result
let a = MySIMD [ 2 ]( 1 , 2 )
let x = concat [ 2 , 2 ]( a , a )
x . dump ()
เวลาในการคอมไพล์ [พารามิเตอร์]: fn concat[len1: Int, len2: Int]
เวลารัน (Args) : fn concat(lhs: MySIMD, rhs: MySIMD)
พารามิเตอร์ไวยากรณ์ PEP695 ในวงเล็บเหลี่ยม []
ตอนนี้ใน Python:
def func ( a : _T , b : _T ) -> _T :
...
ตอนนี้อยู่ในโมโจ:
def func [ T ]( a : T , b : T ) -> T :
...
[Parameters] ได้รับการตั้งชื่อและมีประเภท เหมือนกับค่าปกติ ในโปรแกรม Mojo แต่ parameters[]
จะได้รับการประเมิน ณ เวลาคอมไพล์
โปรแกรมรันไทม์อาจใช้ค่าของ [พารามิเตอร์] - เนื่องจากพารามิเตอร์ได้รับการแก้ไข ณ เวลาคอมไพล์ก่อนที่โปรแกรมรันไทม์จำเป็นต้องใช้ - แต่นิพจน์พารามิเตอร์เวลาคอมไพล์อาจไม่ใช้ค่ารันไทม์
แบบ Self
จาก PEP673
fn __sub__ ( self , rhs : Self ) - > Self :
let result = MySIMD [ size ]()
for i in range ( size ):
result [ i ] = self [ i ] - rhs [ i ]
return result
ในเอกสาร คุณสามารถค้นหาคำว่า Fields ซึ่งเป็นที่รู้จักกันในชื่อ class Attributes ใน Python
ดังนั้นคุณเรียกพวกมันด้วย dot
from DType import DType
let bool_type = DType . bool
from DType import DType
DType . si8
from DType import DType
from SIMD import SIMD , SI8
alias MY_SIMD_DType_si8 = SIMD [ DType . si8 , 1 ]
alias MY_SI8 = SI8
print ( MY_SIMD_DType_si8 == MY_SI8 )
# true
from DType import DType
from SIMD import SIMD , SI8
from Vector import DynamicVector
from String import String
alias a = DynamicVector [ SIMD [ DType . si8 , 1 ]]
alias b = DynamicVector [ SI8 ]
print ( a == b )
print ( a == String )
print ( b == String )
# all true
ดังนั้น String
จึงเป็นเพียงนามแฝงสำหรับบางอย่างเช่น DynamicVector[SIMD[DType.si8, 1]]
VariadicList
สำหรับการทำลายล้าง/คลายแพ็ก/เข้าถึงอาร์กิวเมนต์ from List import VariadicList
fn destructuring_arguments ( * args : Int ):
let my_var_list = VariadicList ( args )
for i in range ( len ( my_var_list )):
print ( "argument" , i , ":" , my_var_list [ i ])
destructuring_arguments ( 1 , 2 , 3 , 4 )
มันมีประโยชน์มากสำหรับการสร้างคอลเลกชันเริ่มต้น เราสามารถเขียนได้ดังนี้:
from Vector import DynamicVector
from StaticTuple import StaticTuple
fn create_vertor () - > DynamicVector [ Int ]:
let st = StaticTuple [ 4 , Int ]( 1 , 2 , 3 , 4 )
var v = DynamicVector [ Int ]( st . __len__ ())
for i in range ( st . __len__ ()):
v . push_back ( st [ i ])
return v
v = create_vertor ()
print ( v [ 0 ], v [ 3 ])
# or
from List import VariadicList
fn create_vertor () - > DynamicVector [ Int ]:
let var_list = VariadicList ( 1 , 2 , 3 , 4 )
var v = DynamicVector [ Int ]( len ( var_list ))
for i in range ( len ( var_list )):
v . push_back ( var_list [ i ])
return v
v = create_vertor ()
print ( v [ 0 ], v [ 3 ])
อ่านเพิ่มเติมเกี่ยวกับฟังก์ชัน def และ fn
from String import String
# String concatenation
print ( String ( "'" ) + String ( 1 ) + "' n " )
# Python's join
print ( String ( "|" ). join ( "a" , "b" , "c" ))
# String format
from IO import _printf as print
let x : Int = 1
print ( "'%i' n " , x . value )
สำหรับสตริง คุณสามารถใช้ Builtin Slice พร้อมจัดรูปแบบ string slice[start:end:step]
from String import String
let hello_mojo = String ( "Hello Mojo!" )
print ( "Till the end:" , hello_mojo [ 0 ::])
print ( "Before last 2 chars:" , hello_mojo [ 0 : - 2 ])
print ( "From start to the end with step 2:" , hello_mojo [ 0 :: 2 ])
print ( "From start to the before last with step 3:" , hello_mojo [ 0 : - 1 : 3 ])
มีปัญหาบางอย่างกับ Unicode เมื่อทำการแบ่งส่วน:
let hello_mojo_unicode = String ( "Hello Mojo!" )
print ( "Unicode efore last 2 chars:" , hello_mojo_unicode [ 0 : - 2 ])
# no result, silents
นี่คือคำอธิบายและการอภิปรายบางส่วน
mbstowcs - แปลงสตริงหลายไบต์เป็นสตริงอักขระแบบกว้าง
มัณฑนากร struct
หรือที่รู้จักในชื่อ Python @dataclass
มันจะสร้างวิธีการ __init__
, __copyinit__
, __moveinit__
ให้คุณโดยอัตโนมัติ
@ value
struct dataclass :
var name : String
var age : Int
โปรดทราบว่าเครื่องมือตกแต่ง @value
ใช้งานได้เฉพาะกับประเภทที่สมาชิก copyable
และ/หรือ movable
ได้
ประเภทจิ๊บจ๊อย มัณฑนากรคนนี้บอก Mojo ว่าประเภทนั้นควรคัดลอกได้ __copyinit__
และ __moveinit__
แบบเคลื่อนย้ายได้ นอกจากนี้ยังบอกให้ Mojo ต้องการส่งค่าในการลงทะเบียน CPU อนุญาตให้ structs
เลือกรับการส่งผ่านใน register
แทนการส่งผ่าน memory
@ register_passable ( "trivial" )
struct Int :
var value : __mlir_type . `!pop.scalar<index>`
มัณฑนากรที่ให้ การควบคุม การปรับแต่งคอมไพเลอร์ อย่างเต็มที่ สั่งให้คอมไพเลอร์อิน ไลน์ ฟังก์ชันนี้เสมอเมื่อมีการเรียกใช้
@ always_inline
fn foo ( x : Int , y : Int ) - > Int :
return x + y
fn bar ( z : Int ):
let r = foo ( z , z ) # This call will be inlined
สามารถวางไว้บนฟังก์ชันที่ซ้อนกันซึ่งจับค่ารันไทม์เพื่อสร้างการปิดการจับแบบ "พาราเมตริก" ช่วยให้การปิดที่บันทึกค่ารันไทม์สามารถส่งผ่านเป็นค่าพารามิเตอร์ได้
@ always_inline
@ parameter
fn test (): return
ตัวอย่างการหล่อบางส่วน
s : StringLiteral
let p = DTypePointer [ DType . si8 ]( s . data ()). bitcast [ DType . ui8 ]()
var result = 0
result += (( p . simd_load [ 64 ]( offset ) >> 6 ) != 0b10 ). cast [ DType . ui8 ](). reduce_add (). to_int ()
let rest_p : DTypePointer [ DType . ui8 ] = stack_allocation [ simd_width , UI8 , 1 ]()
from Bit import ctlz
s : String
i : Int
let code = s . buffer . data . load ( i )
let byte_length_code = ctlz ( ~ code ). to_int ()
DTypePointer - จัดเก็บที่อยู่ด้วย DType ที่กำหนด ช่วยให้คุณสามารถจัดสรร โหลด และแก้ไขข้อมูลด้วยการเข้าถึงการทำงานของ SIMD ได้อย่างสะดวก
from Pointer import DTypePointer
from DType import DType
from Random import rand
from Memory import memset_zero
# `heap`
var my_pointer_on_heap = DTypePointer [ DType . ui8 ]. alloc ( 8 )
memset_zero ( my_pointer_on_heap , 8 )
# `stack or register`
var data = my_pointer_on_heap . simd_load [ 8 ]( 0 )
print ( data )
rand ( my_pointer_on_heap , 4 )
# `data` does not contain a reference to the `heap`, so load the data again
data = my_pointer_on_heap . simd_load [ 8 ]( 0 )
print ( data )
# simd_load and simd_store
var half = my_pointer_on_heap . simd_load [ 4 ]( 0 )
half = half + 1
my_pointer_on_heap . simd_store [ 4 ]( 4 , half )
print ( my_pointer_on_heap . simd_load [ 8 ]( 0 ))
# Pointer move back
my_pointer_on_heap -= 1
print ( my_pointer_on_heap . simd_load [ 8 ]( 0 ))
# Mast free memory
my_pointer_on_heap . free ()
โครงสร้างสามารถลดอันตรายที่อาจเกิดขึ้นจากพอยน์เตอร์ได้โดยการจำกัดการสำรวจ
บทความดีๆ ในบล็อก Mojo Dojo เกี่ยวกับ DTypePointer ที่นี่
รวมถึงตัวอย่างของเขา Matrix Struct และ DTypePointer
ตัวชี้จัดเก็บที่อยู่ให้กับ register_passable type
ใด ๆ และจัดสรรจำนวน n
จำนวนให้กับ heap
from Pointer import Pointer
from Memory import memset_zero
from String import String
@ register_passable # for syntaxt like `let coord = p1[0]` and let it be passed through registers.
struct Coord : # memory-only type
var x : UI8
var y : UI8
var p1 = Pointer [ Coord ]. alloc ( 2 )
memset_zero ( p1 , 2 )
var coord = p1 [ 0 ] # is an identifier to memory on the stack or in a register
print ( coord . x )
# Store the value
coord . x = 5
coord . y = 5
print ( coord . x )
# We need to store the data.
p1 . store ( 0 , coord )
print ( p1 [ 0 ]. x )
# Mast free memory
p1 . free ()
บทความเต็มเกี่ยวกับพอยน์เตอร์
พร้อมตัวอย่างพอยน์เตอร์และโครงสร้าง
Modular Intrinsics เป็น แบ็กเอนด์การดำเนินการ บางประเภท:
Mojo-> MLIR Dialects -> แบ็กเอนด์ดำเนินการด้วยโค้ดเพิ่มประสิทธิภาพและสถาปัตยกรรม
MLIR เป็นแม่มดโครงสร้างพื้นฐานคอมไพเลอร์ที่ใช้การแปลงและการเพิ่มประสิทธิภาพที่หลากหลายสำหรับ ภาษาการเขียนโปรแกรม และ สถาปัตยกรรม ที่แตกต่างกัน
MLIR เองไม่ได้จัดเตรียมฟังก์ชันการทำงานสำหรับการโต้ตอบกับระบบปฏิบัติการ syscalls โดยตรง
ซึ่งเป็นอินเทอร์เฟซระดับต่ำสำหรับบริการระบบปฏิบัติการ โดยทั่วไปจะได้รับการจัดการที่ระดับภาษาโปรแกรมเป้าหมายหรือระบบปฏิบัติการเอง MLIR ได้รับการออกแบบมาให้ไม่เชื่อเรื่องภาษาและเป้าหมาย และจุดสนใจหลักคือการให้การนำเสนอระดับกลางสำหรับการดำเนินการปรับให้เหมาะสม ในการดำเนินการ syscalls ของระบบปฏิบัติการใน MLIR เราจำเป็นต้องใช้ แบ็กเอนด์ เฉพาะเป้าหมาย
แต่ด้วย execution backends
เหล่านี้ โดยพื้นฐานแล้ว เราสามารถเข้าถึง OS syscalls ได้ และเรามีโลกทั้งใบของ C/LLVM/Python อยู่ใต้ฝากระโปรง
มาดูในทางปฏิบัติกันอย่างรวดเร็ว:
from OS import getenv
print ( getenv ( "PATH" ))
print ( getenv ( StringRef ( "PATH" )))
# or like this
from SIMD import SI8
from Intrinsics import external_call
var path1 = external_call [ "getenv" , StringRef ]( StringRef ( "PATH" ))
print ( path1 . data )
var path2 = external_call [ "getenv" , StringRef ]( "PATH" )
print ( path2 . data )
let abs_10 = external_call [ "abs" , SI8 , Int ]( - 10 )
print ( abs_10 )
ในตัวอย่างง่ายๆ นี้ เราใช้ external_call
เพื่อรับตัวแปรสภาพแวดล้อม OS ที่มีประเภทการแคสต์ระหว่างฟังก์ชัน Mojo และ libc เจ๋งมาก ใช่แล้ว!
ฉันมีแนวคิดมากมายจากหัวข้อนี้ และฉันกำลังรอคอยโอกาสที่จะนำไปปฏิบัติเร็วๆ นี้ การดำเนินการสามารถนำไปสู่ผลลัพธ์ที่น่าอัศจรรย์ =)
มาทำสิ่งที่น่าสนใจกันดีกว่า - เรียกใช้ libc function
gethostname
ฟังก์ชั่นมีอินเทอร์เฟซนี้ int gethostname (char *name, size_t size)
เพื่อที่เราสามารถใช้ฟังก์ชันตัวช่วย external_call จากโมดูล Intrinsics หรือเขียน MLIR ของตัวเองได้
ไปกันเถอะรหัส:
from Intrinsics import external_call
from SIMD import SIMD , SI8
from DType import DType
from Vector import DynamicVector
from DType import DType
from Pointer import DTypePointer , Pointer
# We can use `from String import String` but for clarification we will use a full form.
# DynamicVector[SIMD[DType.si8, 1]] == DynamicVector[SI8] == String
# Compile time stuff.
alias cArrayOfStrings = DynamicVector [ SIMD [ DType . si8 , 1 ]]
alias capacity = 1024
var c_pointer_to_array_of_strings = DTypePointer [ DType . si8 ]( cArrayOfStrings ( capacity ). data )
var c_int_result = external_call [ "gethostname" , Int , DTypePointer [ DType . si8 ], Int ]( c_pointer_to_array_of_strings , capacity )
let mojo_string_result = String ( c_pointer_to_array_of_strings . address )
print ( "C function gethostname result code:" , c_int_result )
print ( "C function gethostname result value:" , star_hostname ( mojo_string_result ))
@ always_inline
fn star_hostname ( hostname : String ) - > String :
# [Builtin Slice](https://docs.modular.com/mojo/MojoBuiltin/BuiltinSlice.html)
# string slice[start:end:step]
return hostname [ 0 : - 1 : 2 ]
มาทำบางอย่างกับเว็บกับ Mojo กันดีกว่า เราไม่มีอินเทอร์เน็ตที่ Playground.modular.com แต่เราสามารถขโมยสิ่งที่น่าสนใจ เช่น TCP ในเครื่องเดียวได้
มาเขียนโค้ดไคลเอ็นต์-เซิร์ฟเวอร์ TCP แรกใน Mojo ด้วย PythonInterface
คุณควรสร้างสมุดบันทึกสองเครื่องแยกกัน และเรียกใช้ TCPSocketServer ก่อน จากนั้นจึงเรียก ใช้ TCPSocketClient
รหัสนี้ เวอร์ชัน Python เกือบจะเหมือนกัน ยกเว้น:
with
ไวยากรณ์let
มอบหมายa, b = (1, 2)
หลังจาก TCP Server ใน Mojo เราจะก้าวไปข้างหน้า =)
มันบ้ามาก แต่มาลองใช้เว็บเซิร์ฟเวอร์ Python สมัยใหม่ FastAPI กับ Mojo กันดีกว่า!
เราจำเป็นต้องอัปโหลดโค้ด FastAPI ไปยัง Playground ดังนั้นบนเครื่องท้องถิ่นของคุณทำ
pip install --target=web fastapi uvicorn
tar -czPf web.tar.gz web
และอัปโหลด web.tar.gz
ไปยัง Playground ผ่านทางเว็บอินเตอร์เฟส
จากนั้นเราจำเป็นต้อง install
มัน เพียงใส่ไว้ในโฟลเดอร์ที่เหมาะสม:
% % python
import os
import site
site_packages_path = site . getsitepackages ()[ 0 ]
# install fastapi
os . system ( f"tar xzf web.tar.gz -C { site_packages_path } " )
os . system ( f"cp -r { site_packages_path } /web/* { site_packages_path } /" )
os . system ( f"ls { site_packages_path } | grep fastapi" )
# clean packages
os . system ( f"rm -rf { site_packages_path } /web" )
os . system ( f"rm web.tar.gz" )
from PythonInterface import Python
# Python fastapi
let fastapi = Python . import_module ( "fastapi" )
let uvicorn = Python . import_module ( "uvicorn" )
var app = fastapi . FastAPI ()
var router = fastapi . APIRouter ()
# tricky part
let py = Python ()
let py_code = """lambda: 'Hello Mojo!'"""
let py_obj = py . evaluate ( py_code )
print ( py_obj )
router . add_api_route ( "/mojo" , py_obj )
app . include_router ( router )
print ( "Start FastAPI WEB Server" )
uvicorn . run ( app )
print ( "Done" )
from PythonInterface import Python
let http_client = Python . import_module ( "http.client" )
let conn = http_client . HTTPConnection ( "localhost" , 8000 )
conn . request ( "GET" , "/mojo" )
let response = conn . getresponse ()
print ( response . status , response . reason , response . read ())
ตามปกติ คุณควรสร้างสมุดบันทึกสองเล่มแยกกัน และเรียกใช้ FastAPI ก่อนแล้วจึงเรียก ใช้ FastAPIClient
มีคำถามปลายเปิดมากมาย แต่โดยพื้นฐานแล้ว เราบรรลุเป้าหมายแล้ว
โมโจ ทำได้ดีมาก!
คำถามปลายเปิด:
from PythonInterface import Python
let pyfn = Python . evaluate ( "lambda x, y: x+y" )
let functools = Python . import_module ( "functools" )
print ( functools . reduce ( pyfn , [ 1 , 2 , 3 , 4 ]))
# How to, without Mojo pyfn.so?
def pyfn ( x , y ):
retyrn x + y
อนาคตดูสดใสมาก!
ลิงค์:
Benchmark Mojo vs Numba โดย นิค โวแกน
เวลาที่ใช้โดย Samay Kapadia @Zalando
กำลังเชื่อมต่อกับสนามเด็กเล่นโมโจของคุณจาก VSCode หรือ DataSpell
โดย แม็กซิม แซคส์
from String import String
from PythonInterface import Python
let pathlib = Python . import_module ( 'pathlib' )
let txt = pathlib . Path ( 'nfl.csv' ). read_text ()
let s : String = txt . to_string ()
การใช้งาน libc
from DType import DType
from Buffer import Buffer
from Pointer import Pointer
from String import String , chr
let hello = "hello"
let pointer = Pointer ( hello . data ())
print ( "variant 1" )
var result = String ()
for i in range ( len ( hello )):
result += chr ( pointer . bitcast [ Int8 ](). offset ( i ). load (). to_int ())
print ( result )
print ( "variant 2" )
print ( StringRef ( hello . data ()))
print ( "variant 3" )
print ( StringRef ( pointer . address ))
print ( "variant 4" )
let pm : Pointer [ __mlir_type . `!pop.scalar<si8>` ] = Pointer ( hello . data ())
print ( StringRef ( pm . address ))
print ( "variant 5" )
print ( String ( pointer . address ))
print ( "variant 6" )
let x = Buffer [ 8 , DType . int8 ]( pointer )
let array = x . simd_load [ 10 ]( 0 )
var result = String ()
for i in range ( len ( array )):
result += chr ( array [ i ]. to_int ())
print ( result )
right click
ไฟล์ใน explorer แล้วกด Open With > Editor
select all
แล้ว copy
.ipynb
Github เรนเดอร์อย่างถูกต้อง และหากใครต้องการลองใช้โค้ดใน Playground ก็สามารถคัดลอกและวางโค้ดดิบได้
มันเป็นความเห็นส่วนตัวของฉัน ดังนั้นอย่าตัดสินฉันรุนแรงเกินไป
ฉันไม่สามารถพูดได้ว่า Mojo เป็นภาษาการเขียนโปรแกรมที่ง่ายสำหรับการเรียนรู้ อย่างเช่น Python เป็นตัวอย่าง
ต้องใช้ความเข้าใจ ความอดทน และประสบการณ์อย่างมากในภาษาการเขียนโปรแกรมอื่นๆ
หากคุณต้องการสร้างสิ่งที่ไม่ใช่เรื่องจิ๊บจ๊อย มันจะยากแต่ก็ตลก!
เป็นเวลา 2 สัปดาห์ แล้วตั้งแต่ฉันเริ่มต้น การเดินทาง ครั้งนี้ และฉันตื่นเต้นที่จะเล่าว่าตอนนี้ฉัน คุ้นเคยกับโมโจเป็นอย่างดีแล้ว
ความซับซ้อนของ โครงสร้างและไวยากรณ์ ของมันเริ่ม คลี่คลายต่อหน้าต่อตาฉัน และฉันก็เต็มไปด้วย ความเข้าใจ ที่เพิ่งค้นพบ
ฉันภูมิใจที่จะบอกว่าตอนนี้ฉันสามารถ สร้างโค้ด ในภาษานี้ได้อย่างมั่นใจ ทำให้ฉันสามารถนำ แนวคิด ที่หลากหลาย มาสู่ชีวิตได้
Mojo เป็นภาษาโปรแกรมของ Modular Inc ทำไม Mojo เราพูดคุยกันที่นี่ เกี่ยวกับบริษัท เรารู้จักน้อย แต่มีชื่อที่เจ๋งมาก Modular
ซึ่งสามารถอ้างอิงถึง:
“หรืออีกนัยหนึ่ง Mojo ไม่ใช่เวทย์มนตร์ มันเป็นโมดูลาร์”
ทุกอย่างเกี่ยวกับการประมวลผล การเขียนโปรแกรม AI/ML ชื่อโดเมนที่ดีมากที่อธิบายความหมายของบริษัทได้อย่างถูกต้อง
มีเนื้อหาเพิ่มเติมบางส่วนเกี่ยวกับเรื่องราวของแบรนด์ของ Modular และการช่วยให้ AI ของโมดูลาร์มีมนุษยธรรมผ่านแบรนด์
วันนี้ผมอยากจะเล่าเรื่องเกี่ยวกับปัญหา Python Enum ครับ ในฐานะวิศวกรซอฟต์แวร์ เรามักจะพบสิ่งนี้ในเว็บ สมมติว่าเรามี DataBase Schema (PostgreSQL) พร้อมสถานะ enum
:
CREATE TYPE public .status_type AS ENUM (
' FIRST ' ,
' SECOND '
);
ในโค้ด Python เราต้องการชื่อและค่าเป็นสตริง (สมมติว่าเราใช้ GraphQL กับ ENUM บางประเภทสำหรับส่วนหน้าของเรา) และเราจำเป็นต้องรักษาลำดับไว้และมีความสามารถในการเปรียบเทียบแจงนับเหล่านี้:
order2.status > order1.status > 'FIRST'
ดังนั้นจึงเป็นปัญหาสำหรับภาษาทั่วไปส่วนใหญ่ =) แต่เราสามารถใช้ฟีเจอร์ Python little-known
และแทนที่วิธีการคลาส enum: __new__
MALE -> 1
, FEMALE -> 2
เหมือน PostgreSQL ทำlen
! import enum
from functools import total_ordering
@ total_ordering
@ enum . unique
class BaseUniqueSortedEnum ( enum . Enum ):
"""Base unique enum class with ordering."""
def __new__ ( cls , * args , ** kwargs ):
obj = object . __new__ ( cls )
obj . index = len ( cls . __members__ ) + 1 # This code line is a piece of advice, an insight and a tip!
return obj
# and then boring Python's magic methods as usual...
def __hash__ ( self ) -> int :
return hash (
f" { self . __module__ } _ { self . __class__ . __name__ } _ { self . name } _ { self . value } "
)
def __eq__ ( self , other ) -> bool :
self . _check_type ( other )
return super (). __eq__ ( other )
def __lt__ ( self , other ) -> bool :
self . _check_type ( other )
return self . index < other . index
def _check_type ( self , other ) -> None :
if type ( self ) != type ( other ):
raise TypeError ( f"Different types of Enum: { self } != { other } " )
class Dog ( BaseUniqueSortedEnum ):
# THIS ORDER MATTERS!
BLOODHOUND = "BLOODHOUND"
WEIMARANER = "WEIMARANER"
SAME = "SAME"
class Cat ( BaseUniqueSortedEnum )
# THIS ORDER MATTERS!
BRITISH = "BRITISH"
SCOTTISH = "SCOTTISH"
SAME = "SAME"
# and some tests
assert Dog . BLOODHOUND < Dog . WEIMARANER
assert Dog . BLOODHOUND <= Dog . WEIMARANER
assert Dog . BLOODHOUND != Dog . WEIMARANER
assert Dog . BLOODHOUND == Dog . BLOODHOUND
assert Dog . WEIMARANER == Dog . WEIMARANER
assert Dog . WEIMARANER > Dog . BLOODHOUND
assert Dog . WEIMARANER >= Dog . BLOODHOUND
assert Cat . BRITISH < Cat . SCOTTISH
assert Cat . BRITISH <= Cat . SCOTTISH
assert Cat . BRITISH != Cat . SCOTTISH
assert Cat . BRITISH == Cat . BRITISH
assert Cat . SCOTTISH == Cat . SCOTTISH
assert Cat . SCOTTISH > Cat . BRITISH
assert Cat . SCOTTISH >= Cat . BRITISH
assert hash ( Dog . BLOODHOUND ) == hash ( Dog . BLOODHOUND )
assert hash ( Dog . WEIMARANER ) == hash ( Dog . WEIMARANER )
assert hash ( Dog . BLOODHOUND ) != hash ( Dog . WEIMARANER )
assert hash ( Dog . SAME ) != hash ( Cat . SAME )
# raise TypeError
Dog . SAME <= Cat . SAME
Dog . SAME < Cat . SAME
Dog . SAME > Cat . SAME
Dog . SAME >= Cat . SAME
Dog . SAME != Cat . SAME
จุดสิ้นสุดของเรื่องราว และใช้ ข้อมูลเชิงลึก Python ENUM
นี้เพื่อการเขียนโค้ดที่ดีของคุณ!