چطور numpy-ts به سرعت NumPy رسید
خلاصهٔ کاملتر
نویسنده تعریف میکنه که وقتی ساخت numpy-ts رو شروع کرد همه میگفتن یه کتابخونهی خالص جاوااسکریپت هیچوقت به سرعت NumPy نمیرسه، و آخرش هم معلوم شد حق با اونا بوده. دلیلش اینه که NumPy توی مسیرهای داغش دیگه پایتون نیست، بلکه C و کتابخونههایی مثل BLAS و LAPACK و pocketfft ـه که پشت یه API پایتونی قایم شدن و از SIMD و چند هستهایشدن استفاده میکنن.
اولین هدف numpy-ts سازگاری بود و بعد از چند ماه به پوشش کاملی از API و تستهای تطبیقی با خود NumPy رسید، ولی حدود ۱۵ برابر کندتر بود. نویسنده میگه مشکل از موتورهای جاوااسکریپت نیست؛ یه حلقهی تنگ و monomorphic روی Float64Array تقریباً مثل C کامپایل میشه. مشکل اینه که NumPy حلقهی اسکالر اجرا نمیکنه و هر عمل رو روی چند لِین همزمان انجام میده.
قدم بعدی WebAssembly بود. نویسنده بهجای بازنویسی کل کتابخونه بهصورت یه بلاب بزرگ نیتیو، کرنلهای حساس رو به ماژولهای کوچیک و مستقل WASM منتقل کرد و برای این کار Zig رو انتخاب کرد چون آرتیفکت کوچیک تولید میکنه و کنترل مستقیم روی حافظه میده. این کار فاصله رو از ۱۵ برابر به حدود ۲ برابر رسوند، ولی انگار سرعت به یه سقف خورده بود.
نویسنده میگه گمان اولش این بود که سربار فراخوانی بین جاوااسکریپت و WASM مقصره، ولی مشکل واقعی کپی بود. توی طراحی اولیه دادهها توی TypedArray های جاوااسکریپت زندگی میکردن و برای هر کرنل باید به حافظهی WASM کپی میشدن و نتیجه دوباره برمیگشت. توی کد واقعی که پر از عملیات زنجیرهایه، این مالیاتِ کپی رفتوبرگشت به هزینهی اصلی تبدیل میشه.
راهحل این بود که خودِ دادهی آرایه هم داخل حافظهی خطی WASM ذخیره بشه و جاوااسکریپت فقط مدل شیءگرا، شکل، stride و متادیتای dtype رو نگه داره. اونوقت کرنل دیگه لازم نیست ورودی رو کپی کنه چون از قبل اونجاست و خروجی هم همونجا ساخته میشه؛ فقط اشارهگر و متادیتا رد و بدل میشه. نویسنده برای این کار یه allocator سفارشی با free-list جداسازیشده نوشت که با الگوی تخصیص و آزادسازی آرایهها جور بود.
نتیجهی این تغییر معماری این شد که numpy-ts روی مجموعهی بنچمارک به سرعت NumPy رسید و بهطور میانگین ۱.۱۱ برابر سریعتر شد، البته NumPy هنوز توی بعضی حوزهها مثل توابع مثلثاتی، مرتبسازی، FFT و اعداد مختلط جلوتره. نویسنده تأکید میکنه که این معماری هزینههایی هم داره: حالا باید خودت مدیریت حافظه رو با FinalizationRegistry و الگوی using انجام بدی، پشتیبانی از dtype هایی مثل float16 سختتره، و بستهبندی برای Node و Bun و Deno و مرورگرها هم پیچیدهتر شده.
نکات کلیدی:
- numpy-ts یه پیادهسازی کامل NumPy برای تایپاسکریپت با پوشش بالای API و تست تطبیقی با خود NumPy ـه.
- فقط بردن کرنلها به WASM فاصله رو از ۱۵ برابر به ۲ برابر رسوند، نه بیشتر.
- گلوگاه واقعی کپی مداوم داده بین حافظهی جاوااسکریپت و WASM بود.
- با نگهداری دادهی آرایه داخل حافظهی WASM و پاسدادن اشارهگر، کپی حذف شد و سرعت به NumPy رسید.
- این کار یه allocator سفارشی و مدیریت دستی حافظه رو لازم میکنه.




