1 คะแนน โดย GN⁺ 2025-02-16 | 3 ความคิดเห็น | แชร์ทาง WhatsApp
  • ใน Go 1.24 มีการขยายความสามารถที่เกี่ยวข้องกับ WebAssembly (Wasm)
  • มีการเพิ่ม directive go:wasmexport ทำให้สามารถเรียกฟังก์ชัน Go จากภายนอกโมดูล Wasm ได้
  • ยังรองรับโหมด build แบบ “reactor” สำหรับ WASI ทำให้สามารถรันโค้ดในสถานะที่ทำงานต่อเนื่องได้เป็นเวลานาน
  • สิ่งนี้เปิดทางให้ขยายแอปพลิเคชัน Go ในสภาพแวดล้อม Wasm ได้อย่างยืดหยุ่นมากขึ้น

WebAssembly and the WebAssembly System Interface

  • WebAssembly เป็นฟอร์แมตไบนารีที่สร้างขึ้นเพื่อรันโค้ดระดับล่างประสิทธิภาพสูงในเว็บเบราว์เซอร์
  • ปัจจุบันถูกนำไปใช้อย่างกว้างขวางนอกเบราว์เซอร์ด้วยเช่นกัน และสามารถโต้ตอบกับทรัพยากรของระบบผ่าน WebAssembly System Interface (WASI) ได้
  • Go เริ่มรองรับการคอมไพล์ไปยัง Wasm ผ่านพอร์ต js/wasm ตั้งแต่เวอร์ชัน 1.11 และในเวอร์ชัน 1.21 ได้เพิ่มพอร์ตใหม่ผ่าน GOOS=wasip1 เพื่อกำหนดเป้าหมาย API system call ของ WASI preview 1

Export ฟังก์ชัน Go เป็น Wasm ด้วย go:wasmexport

  • ใน Go 1.24 มีการเพิ่ม directive go:wasmexport ใหม่ ทำให้สามารถเปิดเผยฟังก์ชัน Go เป็น export เพื่อให้เรียกจากภายนอกโมดูล Wasm ได้
  • ตัวอย่างเช่น หากประกาศ //go:wasmexport add แล้วเขียนฟังก์ชันตามนั้น Wasm host ก็จะสามารถเรียกฟังก์ชันดังกล่าวได้
  • แนวทางนี้คล้ายกับ directive export ของ cgo แต่ถูกทำให้เรียบง่ายกว่า

Building a WASI Reactor

  • WASI “reactor” หมายถึงโมดูล WebAssembly ที่ทำงานต่อเนื่องและตอบสนองต่อ event หรือ request ได้
  • ใน Go 1.24 รองรับการ build แบบ WASI reactor ด้วยออปชัน -buildmode=c-shared
  • build flag นี้จะสั่ง linker ไม่ให้สร้างฟังก์ชัน _start (entry point ของ command module) แต่ให้สร้างฟังก์ชัน _initialize แทน
    • reactor จะถูกเริ่มต้นผ่านฟังก์ชัน _initialize และต้องเรียกฟังก์ชันนี้ก่อนแทนที่จะเริ่มที่ฟังก์ชัน main
  • เมื่อนำไปใช้ร่วมกับ runtime อย่าง Wazero หลังจากเรียก _initialize แล้ว ก็สามารถเรียกฟังก์ชันที่ export ไว้ซ้ำได้ตามต้องการ
  • วิธีนี้มีประโยชน์ในสภาพแวดล้อมที่ใช้ Wasm เป็นกลไกปลั๊กอินหรือส่วนขยายของแอปพลิเคชัน

รองรับชนิดข้อมูลระหว่างโฮสต์และไคลเอนต์ได้หลากหลายขึ้น

  • ใน Go 1.24 ข้อจำกัดของชนิดข้อมูลสำหรับพารามิเตอร์/ค่าที่ส่งกลับของฟังก์ชันที่เรียกผ่าน go:wasmimport ถูกผ่อนคลายลง
  • ตัวอย่างเช่น สามารถส่งค่า bool, string, พอยน์เตอร์ int32, พอยน์เตอร์โครงสร้างข้อมูล เป็นต้น ได้
    • อย่างไรก็ตาม ยังมีข้อจำกัดอยู่จากความแตกต่างระหว่างสภาพแวดล้อม 64 บิตและ 32 บิต เป็นต้น
  • สิ่งนี้ช่วยให้เขียนแอปพลิเคชัน Go Wasm ได้เป็นธรรมชาติและสะดวกยิ่งขึ้น พร้อมลดการแปลงชนิดข้อมูลที่ไม่จำเป็น

ข้อจำกัด

  • Wasm เป็นสถาปัตยกรรมแบบเธรดเดียวที่ไม่มีการประมวลผลแบบขนาน
  • ฟังก์ชัน go:wasmexport สามารถสร้าง goroutine ใหม่ได้ แต่ถ้าฟังก์ชันนั้นสร้าง goroutine ที่ทำงานเบื้องหลัง มันจะไม่ทำงานต่อหลังจาก go:wasmexport คืนค่าแล้ว จนกว่าจะมีการเรียกกลับเข้าสู่โมดูล Wasm ที่สร้างด้วย Go อีกครั้ง
  • แม้ว่าข้อจำกัดบางส่วนของชนิดข้อมูลจะถูกผ่อนคลายแล้ว แต่ชนิดข้อมูลที่ใช้ร่วมกับฟังก์ชัน go:wasmimport และ go:wasmexport ได้ก็ยังคงมีข้อจำกัดอยู่
    • การส่งชนิดข้อมูลเชิงประกอบที่มีพอยน์เตอร์ยังคงมีข้อจำกัด

บทสรุป

  • การเพิ่มความสามารถในการ build แบบ WASI reactor และฟีเจอร์ go:wasmexport ใน Go 1.24 เป็นการปรับปรุงที่ช่วยขยาย ecosystem ของ Go บน Wasm อย่างมาก
  • สิ่งนี้ช่วยให้นักพัฒนาสามารถสร้างแอปพลิเคชัน Wasm ที่อิงกับ Go ได้หลากหลายยิ่งขึ้น และเปิดความเป็นไปได้ใหม่ให้ Go ใน ecosystem ของ Wasm

3 ความคิดเห็น

 
click 2025-02-16

ก่อนที่ Wasm/gc จะถูกนำมาใช้อย่างแพร่หลาย ผมคิดว่าน่าจะดีกว่าถ้าพัฒนาเป้าหมาย wasm ด้วยภาษาที่ไม่มี gc

 
xguru 2025-02-16

ในโน้ตการออก Go 1.24 อธิบายไว้สั้น ๆ แต่เป็นอัปเดตที่สำคัญกว่านั้นมากครับ

 
GN⁺ 2025-02-16
ความเห็นจาก Hacker News
  • มีปัญหาใหญ่ตรงที่ไบนารี WASM ที่สร้างด้วย Go มีขนาดใหญ่มาก TinyGo ช่วยแก้ปัญหานี้ได้ แต่คอมไพล์ช้าและต้องระวังเรื่องการเลือกไลบรารี ถ้าจะเอาชนะข้อจำกัดของทั้งสองฝั่งได้ก็ต้องใช้ความอดทนมาก

    • ถ้าจะลองใช้ Go WASM บน Cloudflare workers ต้องสมัครแพ็กเกจแบบเสียเงินเพราะขนาดไบนารี
    • ครั้งล่าสุดที่ลอง hello-world ยังรันได้ แต่พอซับซ้อนกว่านั้นก็เกินข้อจำกัดด้านขนาด
    • น่าเสียดาย
  • น่าทึ่งมาก เรื่องที่ควรจำไว้คือ:

    • งาน WebAssembly ของ Go ถูกออกแบบและพัฒนาโดยอาสาสมัคร ไม่ใช่โดยทีม Go ดังนั้นกำหนดการจึงขึ้นอยู่กับเวลาว่างของอาสาสมัคร
  • จำไม่ค่อยได้ว่าก่อน Go 1.24 จะยังไม่สามารถ export ฟังก์ชัน Go ไปยัง JS ได้หรือไม่ เหมือนจะจำได้ว่าเมื่อก่อนก็เรียกใช้ฟังก์ชัน Go ที่ export ไว้จาก JS ได้ไม่มีปัญหา

    • ถ้ามีคำอธิบายว่า capability WASI แบบใหม่ปรับปรุงจากเดิมอย่างไรบ้างก็คงจะช่วยได้ (นอกเหนือจากรองรับชนิดข้อมูลได้มากขึ้นผ่าน FFI)
    • คำถามที่สอง: เราสามารถ cast พอยน์เตอร์เป็นจำนวนเต็มเพื่อดึงสตริงและชนิดข้อมูลที่ซับซ้อนจาก instance memory ของโมดูล WASM ได้ ถ้ารับประกันได้ว่า binary representation ของชนิดข้อมูลของฉันใน Go มีความเสถียร วิธีส่งพอยน์เตอร์เข้าไปยังโมดูล WASM ที่สร้างเมื่อใช้ goos=wasip1 นี้ยังใช้ได้อยู่หรือไม่
  • ดูเหมือนว่าจะ "เป็น Go" มากกว่าถ้า export ฟังก์ชันทั้งหมดที่ขึ้นต้นด้วยตัวพิมพ์ใหญ่ในแพ็กเกจ main เพราะการ export ทำงานแบบนี้ในภาษาอยู่แล้ว จึงควรใช้ compiler directive เฉพาะตอนที่ต้องการตั้งชื่ออย่างชัดเจนให้กับสิ่งที่ขึ้นต้นด้วยตัวพิมพ์เล็ก

    • นี่เหมือนกับแนวทาง export ของ cgo ที่มีอยู่เดิม เป็นการทำตามตัวอย่างก่อนหน้า เรื่องการใช้งานก็ยังอยู่นอกตัวภาษา
  • ไม่มีการพูดถึงการทำงานร่วมกับ WASM Component Model

  • สงสัยว่าการทำ garbage collection ของ Go และ WASM ทำงานอย่างไร

  • อยากให้มีภาษาระดับล่างที่มี strong type และรองรับ WASM ได้ยอดเยี่ยม

  • สงสัยว่าจะ debug โมดูล WASM ที่กำลังรันอยู่ในโปรแกรมโฮสต์อย่างไร

  • กังวลว่าความต้องการฟีเจอร์ WASM เพิ่มเติมอาจทำลาย ecosystem ที่ยังอายุน้อยอย่างถาวรได้ ฟีเจอร์ส่วนใหญ่ที่ Go เพิ่มเข้าไปใน WASM น่าจะทำได้แบบ native อยู่แล้วถ้าข้อเสนอ Component Model ถูกรวมเข้ามาก่อนหน้านี้

    • มาตรฐานพัฒนาอย่างช้า ๆ และเมื่อการนำไปใช้เพิ่มขึ้น ก็มีความเสี่ยงว่าจะต้องรองรับฟีเจอร์นอกมาตรฐานอย่าง WASI ไปตลอดกาล