برنامه نویسی

با نگاهی به جلو به WASIP3 – جامعه dev

توسط: Joel Dice

پیش نمایش رابط سیستم WebAssembly 3 (یا WASIP3 برای کوتاه) نسخه اصلی بعدی WASI است ، مجموعه ای از API های ردیابی استاندارد برای توسعه برنامه های قابل حمل با WebAnsembly. این نسخه شامل پیشرفت های قابل توجهی در مدل مؤلفه اصلی – از جمله پشتیبانی برای کلاس اول ، همزمانی قابل ترکیب – در حالی که سازگاری با نسخه WASIP2 موجود را حفظ می کند.

در این پست ، ما ویژگی های جدیدی را با WASIP3 خلاصه خواهیم کرد ، به وضعیت تلاش های اجرای آن نگاه می کنیم و در نهایت یک نمونه در دنیای واقعی ایجاد می کنیم که از آن ویژگی های جدید استفاده می کند.

درباره WASI و مدل مؤلفه WebAssembly

WASI (رابط سیستم WebAssembly) مجموعه ای از رابط هایی است که هر دو ویژگی سیستم عامل سنتی (به عنوان مثال پرونده I/O ، ساعت و شبکه) و همچنین ویژگی های تخصصی تر مانند خدمات ابری (HTTP ، دسترسی به پایگاه داده ، پیام رسانی و غیره) ، انتزاع برای سیستم های تعبیه شده ، رمزنگاری و غیره را شامل می شود.

تا کنون ، WASI دو نسخه نقطه عطف داشته است: 0.1 (AKA WASIP1 ، “پیش نمایش 1”) و 0.2 (AKA WASIP2 ، “پیش نمایش 2”). دومی در اوایل سال گذشته منتشر شد و بر اساس مدل کامپوننت ساخته شده است ، یک استاندارد پیشنهادی برای بیان رابط سطح بالا از یک برنامه WASM یا کتابخانه ، امکان استفاده مجدد از کد زبان متقاطع و جداسازی وابستگی ایمن را فراهم می کند.

قبل از انتشار WASIP2 ، تعدادی از ما در اتحاد Bytecode قبلاً در حال نمونه سازی پایه های WASIP3 بودیم و ما از آن زمان پیشرفت زیادی داشته ایم. اگرچه هنوز کارهای مهمی وجود دارد که قبل از انتشار آن در اواخر سال جاری انجام شود ، اما انتظار داریم عکس های نامزد انتشار را در دو ماه آینده انجام دهیم ، با پشتیبانی آزمایشی برای آن دسته از عکسهای فوری که به زودی در چرخش و سایر زمان های محبوب در حال فرود آمدن هستند. این زمان های اجرا از WASI برای فراهم کردن یک محیط استاندارد برای ماژول های WebAssembly برای تعامل با سیستم میزبان استفاده می کنند.

ویژگی های جدید در WASIP3

موضوع اصلی WASIP3 همزمانی سازنده است. نسخه های قبلی از I/O از طریق A پشتیبانی می کنند poll عملکردی که مجموعه ای از دسته ها را نشان می دهد که وظایف در حال پیشرفت را نشان می دهد ، مسدود می شود تا حداقل یکی از آنها تکمیل شود. این برای بسیاری از اهداف بسیار عالی عمل می کند ، اما باعث می شود مؤلفه های آهنگسازی غیر عملی باشند که بیش از یکی از آنها به طور همزمان نیاز به انجام I/O داشته باشند. فقط یک نفر می تواند تماس بگیرد poll در یک زمان ، که در طی آن هیچ یک از دیگران نمی توانند پیشرفت کنند.

در مقابل ، WASIP3 مبتنی بر دو ویژگی مهم مدل جدید مؤلفه است:

  • یک تابع ناهمزمان ABI: این به مؤلفه ها اجازه می دهد تا توابع را با استفاده از ABI همزمان موجود یا ABI جدید ناهمزمان وارد کنند و یا واردات کنند. علاوه بر این ، با اتصال یکپارچه واردات ASYNC به توابع همگام سازی شده و برعکس ، از مشکل رنگ آمیزی عملکرد جلوگیری می کند.

  • پشتیبانی از داخلی ، عمومی stream وت future انواع ، ارائه ارتباطات میزبان کارآمد ، اختیاری ناهمزمان ، مؤلفه و مؤلفه <->.

با هم ، این ویژگی ها همزمان را به یک مفهوم درجه یک در مدل کامپوننت تبدیل می کنند و به تعداد دلخواه کارهای مهمان اجازه می دهند تا به طور همزمان در همان نمونه مؤلفه اجرا شوند. علاوه بر این ، مؤلفه هایی که از ASYNC ABI جدید استفاده می کنند ممکن است با سایر اجزای بدون خطر مسدود شدن تشکیل شوند وقتی یکی از این مؤلفه ها یک تماس همزمان را برقرار می کند. در این حالت ، زمان اجرای میزبان متوجه تماس مسدود شده ، وظیفه ای را که ساخته شده است به حالت تعلیق در می آورد و به مؤلفه اصلی اجازه می دهد تا به اجرای خود ادامه دهد.

با تشکر از این ویژگی های جدید ، تعاریف انواع رابط WebAssembly (WIT) برای 0.3 در مقایسه با همتایان 0.2 آنها به طور قابل توجهی ساده شده است. به عنوان مثال ، در حالی که wasi:http@0.2.4 شامل 11 نوع منبع مجزا ، wasi:http@0.3.0-draft فقط به 5 نیاز دارد. به همین ترتیب ، مراسم مورد نیاز برای انجام یک عمل ناهمزمان با WASIP2 – ایجاد یک pollable، اضافه کردن آن به یک لیست به همراه هر چیز دیگری که قصد انتظار برای انتظار دارید ، تماس بگیرید poll، و اعزام رویدادها که براساس آن pollableS آماده است – با یک تماس واحد جایگزین شده است async در زبان برنامه نویسی خود در انتخاب کار کنید.

وضعیت WASIP3

مشخصات مدل کامپوننت شامل شرح کاملی از ASYNC ABI ، جریان ها ، آینده ها و توابع داخلی مرتبط است (به دنبال نماد 🔀) باشید. توجه داشته باشید که با کسب تجربه اجرای بیشتر ، این مشخصات هنوز تصفیه شده است ، اما ما انتظار نداریم که بین اکنون و انتشار WASIP3 تغییر اساسی داشته باشد.

پیش نویس 0.3 رابط برای هر یک از پروژه های اصلی WASI نوشته شده است:

اجرای عاقلانه ، جدیدترین wasm-tools انتشار شامل پشتیبانی کامل برای تجزیه ، انتشار ، چاپ و غیره با استفاده از ویژگی های جدید Async است. به همین ترتیب ، آخرین wit-bindgen نسخه های پشتیبانی از تولید اتصالات زنگ زدگی ایدیوماتیک که از آن ویژگی ها استفاده می کنند ، با پشتیبانی از سایر زبانها در راه است.

پشتیبانی از زمان اجرا میزبان برای ویژگی های جدید مدل مؤلفه و WASIP3 در حال توسعه است wasip3-prototyping repo برای Wasmtime و در jco repo

wasi-http نمونه ظروف وسط

بیایید ببینیم از WASIP3 با نوشتن یک ساده استفاده می شود wasi:http درخواست کنترل در زنگ زدگی ، سپس آن را با یک مؤلفه میان افزار که شفاف بدنه پاسخ را فشرده می کند ، تهیه کنید.

ابتدا چند ابزار برای کمک به ما در ساخت و اجرای قطعات نصب خواهیم کرد. با توجه به اینکه کار پیاده سازی WASIP3 از این نوشتن هنوز در حال انجام است ، ما از نسخه های خاص این ابزارها استفاده خواهیم کرد که شناخته شده است که با هم کار می کنند. نسخه های بعدی ممکن است کار کنند ، اما ممکن است از عکس فوری ناسازگار از مشخصات استفاده کنند.

🚧 توجه داشته باشید که ، از آنجا که P3 یک کار در حال پیشرفت است ، بخش اعظم ابزار و هزینه های ارگونومیک هنوز وجود ندارد. این بدان معناست که در حال حاضر کار اضافی و دیگ بخار لازم برای ساخت اجزای WASIP3 در مقایسه با WASIP2 وجود دارد. در این مثال ، ما از نماد 🚧 برای اشاره به داربست اضافی استفاده می کنیم که با نزدیک شدن به یک نسخه غیر ضروری می شود.

دستورات زیر یک پوسته به سبک یونیکس (به عنوان مثال Linux ، MacOS یا WSL2) با آن فرض می کنند curl وت git نصب شده این دستورات زنگ زدگی را نصب می کنند ، wasm-tools، یک چنگال موقت چرخش با wasi:http@0.3.0-draft پشتیبانی ، کپی از پرونده های مربوط به WIT که ما برای تولید اتصالات استفاده خواهیم کرد و یک ماژول آداپتور که هنگام تولید قطعات از آن استفاده خواهیم کرد.

🚧 بیشتر این مراحل یک بار غیر ضروری خواهد بود wasm32-wasip3 یک سکوی هدف زنگ زدگی Offical و wasi جعبه از آن پشتیبانی می کند. 🚧

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target install wasm32-wasip1
cargo install --locked --version 1.227.1 wasm-tools
cargo install --locked --git https://github.com/dicej/spin --branch wasi-http-p3-demo spin-cli
git clone https://github.com/WebAssembly/wasi-http -n && (cd wasi-http && git checkout 505ebdb9)
curl -OL https://github.com/bytecodealliance/wasmtime/releases/download/v30.0.2/wasi_snapshot_preview1.reactor.wasm
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بعد ، ما یک “سلام ، جهان” می نویسیم wasi:http درخواست کنترل کننده ، ایجاد سه پرونده:

  • spin.toml: پرونده مانیفست که برنامه چرخش ما را توصیف می کند:
spin_manifest_version = 2

application.name = "hello"

[[trigger.http]]
route = "/..."
component = "hello"

[component.hello]
source = "hello.wasm"
# 🚧 The `wasm-tools component new` command will be unnecessary once Rust has
# proper `wasm32-wasip3` support. 🚧
build.command = """
cargo build --manifest-path hello/Cargo.toml --release --target wasm32-wasip1 \
  && wasm-tools component new --skip-validation \
       hello/target/wasm32-wasip1/release/hello.wasm \
       -o hello.wasm --adapt wasi_snapshot_preview1.reactor.wasm
"""
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  • hello/Cargo.toml: فایل پیکربندی پروژه و وابستگی برای پروژه Rust ما:
[package]
name = "hello"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies.wit-bindgen]
git = "https://github.com/bytecodealliance/wit-bindgen"
rev = "d73c073b"

[dependencies.wit-bindgen-rt]
git = "https://github.com/bytecodealliance/wit-bindgen"
rev = "d73c073b"
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

hello/src/lib.rs: کد منبع برای مؤلفه ما:

// 🚧 Once the `wasi` crate supports WASIp3, we'll be able to use its
// pre-generated bindings rather then generate them on-the-fly with
// `wit-bindgen` as we do here: 🚧
wit_bindgen::generate!({
    path: "../wasi-http/wit-0.3.0-draft",
    world: "wasi:http/proxy",
    async: {
        exports: [
            "wasi:http/handler@0.3.0-draft#handle",
        ]
    },
    generate_all,
});

use {
    wasi::http::types::{Body, ErrorCode, Headers, Request, Response},
    wit_bindgen_rt::async_support::{self, futures::SinkExt},
};

struct Component;
export!(Component);

impl exports::wasi::http::handler::Guest for Component {
    async fn handle(_request: Request) -> Result {
        let (mut tx, rx) = wit_stream::new();

        async_support::spawn(async move {
            _ = tx.send(b"Hello, WASIp3!".into()).await;
        });

        Ok(Response::new(Headers::new(), Some(Body::new(rx).0)))
    }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اکنون می توانیم آن را بسازیم و آن را اجرا کنیم:

spin build -u
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سپس ، در یک ترمینال دیگر ، می توانیم یک درخواست ارسال کنیم:

curl -i localhost:3000
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اگر همه خوب پیش رفت ، باید چیزی مانند:

HTTP/1.1 200 OK
transfer-encoding: chunked
date: Tue, 11 Mar 2025 16:38:58 GMT

Hello, WASIp3!
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در مرحله بعد ، ما مؤلفه دیگری را می نویسیم که می توانیم با اولین مورد برای افزودن پشتیبانی از فشرده سازی بدن پاسخ ، تشکیل دهیم. ما دو پرونده جدید ایجاد خواهیم کرد:

  • middleware/Cargo.toml: فایل پیکربندی پروژه و وابستگی برای پروژه Rust ما:
[package]
name = "middleware"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies.wit-bindgen]
git = "https://github.com/bytecodealliance/wit-bindgen"
rev = "d73c073b"

[dependencies.wit-bindgen-rt]
git = "https://github.com/bytecodealliance/wit-bindgen"
rev = "d73c073b"

[dependencies.flate2]
version = "1.0.28"
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  • middleware/src/lib.rs: کد منبع برای مؤلفه ما:
// 🚧 Once the `wasi` crate supports WASIp3, we'll be able to use its
// pre-generated bindings rather then generate them on-the-fly with
// `wit-bindgen` as we do here: 🚧
wit_bindgen::generate!({
    path: "../wasi-http/wit-0.3.0-draft",
    world: "wasi:http/proxy",
    async: {
        imports: [
            "wasi:http/handler@0.3.0-draft#handle",
        ],
        exports: [
            "wasi:http/handler@0.3.0-draft#handle",
        ]
    },
    generate_all,
});

use {
    flate2::{write::DeflateEncoder, Compression},
    std::{io::Write, mem},
    wasi::http::{
        handler,
        types::{Body, ErrorCode, Headers, Request, Response},
    },
    wit_bindgen_rt::async_support::{
        self,
        futures::{SinkExt, StreamExt},
    },
};

struct Component;
export!(Component);

impl exports::wasi::http::handler::Guest for Component {
    /// Forward the specified request to the imported `wasi:http/handler`,
    /// encoding the response body if the client has provided an
    /// `accept-encoding: deflate` header.
    async fn handle(request: Request) -> Result {
        // 🚧 Since we're using the auto-generated bindings directly, the code
        // below is a bit verbose.  We expect crates like
        // [wstd](https://docs.rs/wstd) will provide types, traits, and
        // functions to help make code like this more concise. 🚧

        // First, extract the parts of the request and check for (and remove)
        // the `accept-encoding` header.

        let method = request.method();
        let scheme = request.scheme();
        let authority = request.authority();
        let path_with_query = request.path_with_query();
        let (headers, body) = Request::into_parts(request);
        let mut headers = headers.entries();

        let mut accept_deflated = false;
        headers.retain(|(key, value)| {
            if "accept-encoding" == key.as_str() {
                accept_deflated |= std::str::from_utf8(&value)
                    .map(|v| v.contains("deflate"))
                    .unwrap_or(false);
                false
            } else {
                true
            }
        });

        // Synthesize a request from the parts collected above and pass it to
        // the imported `wasi:http/handler`.

        let inner_request = Request::new(
            Headers::from_list(&headers).unwrap(),
            body,
            None
        );
        inner_request.set_method(&method).unwrap();
        inner_request.set_scheme(scheme.as_ref()).unwrap();
        inner_request
            .set_path_with_query(path_with_query.as_deref())
            .unwrap();
        inner_request.set_authority(authority.as_deref()).unwrap();

        let response = handler::handle(inner_request).await?;

        // Now that we have the response, extract the parts and optionally
        // compress the body if applicable.

        let status_code = response.status_code();
        let (headers, body) = Response::into_parts(response);
        let mut headers = headers.entries();
        let body = if accept_deflated {
            if let Some(body) = body {
                // Remove the `content-length` header, if any, since we'll be
                // using chunked encoding instead.
                headers.retain(|(name, _value)| name != "content-length");
                // Add a header to indicate the encoding.
                headers.push(("content-encoding".into(), b"deflate".into()));

                // Spawn a task to pipe and encode the original response body and
                // trailers into a new response we'll create below.  This will run
                // concurrently with the caller's code (i.e. it won't necessarily
                // complete before we return a value).

                let (mut pipe_tx, pipe_rx) = wit_stream::new();

                async_support::spawn(async move {
                    let mut body_rx = body.stream().unwrap().0;
                    let mut encoder = DeflateEncoder::new(
                        Vec::new(),
                        Compression::fast()
                    );
                    while let Some(Ok(chunk)) = body_rx.next().await {
                        encoder.write_all(&chunk).unwrap();
                        pipe_tx.send(mem::take(encoder.get_mut())).await.unwrap();
                    }
                    pipe_tx.send(encoder.finish().unwrap()).await.unwrap();
                });

                Some(Body::new(pipe_rx).0)
            } else {
                None
            }
        } else {
            body
        };

        // While the above task (if any) is running, synthesize a response from
        // the parts collected above and return it.

        let response = Response::new(Headers::from_list(&headers).unwrap(), body);
        response.set_status_code(status_code).unwrap();

        Ok(response)
    }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

و سپس ما ویرایش خواهیم کرد spin.toml پرونده ای که قبلاً ایجاد کردیم تا مؤلفه جدید خود را بسازیم و آن را با نسخه اصلی تهیه کنیم:

spin_manifest_version = 2

application.name = "hello"

[[trigger.http]]
route = "/..."
component = "hello"

[component.hello]
source = "composed.wasm"
# 🚧 The `wasm-tools component new` commands will be unnecessary once Rust has
# proper `wasm32-wasip3` support. 🚧
build.command = """
cargo build --manifest-path hello/Cargo.toml \
       --release --target wasm32-wasip1 \
  && wasm-tools component new --skip-validation \
       hello/target/wasm32-wasip1/release/hello.wasm \
       -o hello.wasm --adapt wasi_snapshot_preview1.reactor.wasm \
  && cargo build --manifest-path middleware/Cargo.toml \
       --release --target wasm32-wasip1 \
  && wasm-tools component new --skip-validation \
       middleware/target/wasm32-wasip1/release/middleware.wasm \
       -o middleware.wasm --adapt wasi_snapshot_preview1.reactor.wasm \
  && wasm-tools compose --skip-validation middleware.wasm -d hello.wasm \
       -o composed.wasm
"""
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اکنون می توانیم ترکیب را بسازیم و اجرا کنیم:

spin build -u
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

سپس ، در یک ترمینال دیگر ، می توانیم یک درخواست ارسال کنیم:

curl --compressed -i localhost:3000
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اگر همه خوب پیش رفت ، باید چیزی مانند:

HTTP/1.1 200 OK
content-encoding: deflate
transfer-encoding: chunked
date: Tue, 11 Mar 2025 16:52:13 GMT

Hello, WASIp3!
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

توجه داشته باشید که ، در حالی که ما از زنگ زدگی برای نوشتن هر دو مؤلفه فوق استفاده کردیم ، ما می توانستیم به راحتی یکی از آنها را در پایتون و دیگری در JavaScript نگاشته باشیم-مدل مؤلفه استفاده مجدد از کد زبان-آگنوستیک را امکان پذیر می کند ، بنابراین می توانید از بهترین ابزار برای هر شغل استفاده کرده و بدون در نظر گرفتن زبان اجرای آنها به راحتی از اجزای شخص ثالث استفاده کنید.

علاوه بر این ، اگرچه ما از آن استفاده کرده ایم wasi:http پرونده های WIT برای تعریف رابط بین مؤلفه هایی که ما ساخته ایم ، می توانیم به راحتی فایل WIT اختصاصی خودمان ، خاص دامنه خود را نوشتیم و به جای آن از آن استفاده کردیم. در این حالت ، ما همه ویژگی های مدل یکسان را در اختیار ما قرار می دهیم:

  • یک سیستم از نوع غنی که از سفارشی پشتیبانی می کند recordبا variantوت resource انواع و غیره
  • futureو streamS (با انواع بار خودسرانه) که محاسبه معوق و I/O را نشان می دهد
  • واردات و صادرات اختیاری ناهمزمان
  • ترکیب زبانی
  • جعبه ماسه ای ایمن

مراحل بعدی

اگرچه WASIP3 هنوز منتشر نشده است ، و پیاده سازی ها هنوز برای استفاده از تولید آماده نیستند ، اکنون زمان بسیار خوبی برای آزمایش با آن و ارائه بازخورد با باز کردن موارد مربوط به repo Spec یا repo WASIP3 است. این که آیا شما در حال توسعه اجزای WASM هستید یا تعبیه میزبان سفارشی برای اجرای مؤلفه ها ، ما دوست داریم ورودی شما را داشته باشیم. و اگر شما یک مجری زبان هستید که به دنبال اضافه کردن پشتیبانی همزمانی برای اهداف WASM هستید ، ما از ورودی شما نیز قدردانی می کنیم.

سرانجام ، اگر شما علاقه مند به کمک به ما در پایان و کشتی WASIP3 هستید ، دریغ نکنید که در کانال WASI ZULIP دسترسی پیدا کنید و از هیئت مدیره پروژه دیدن کنید تا ببینید چه کاری باید انجام شود.

تصدیق

طراحی و اجرای WASIP3 از ابتدا یک تلاش مشترک بوده است. در اینجا تعدادی از مشارکت کنندگان قابل توجه وجود دارد:

  • لوک واگنر با استحکام (طراحی ، مشخصات و اجرای مرجع پایتون)
  • بیلی هیز ، رومی ولوساتوکس ، و ویکتور AdossiCosmonic (به روزرسانی های شوخ طبعی ، اجرای میزبان WASIP3 ، اجرای JCO ، جریان/خطای آینده)
  • Tomasz Andrzejak و Yoshua WuytsMicrosoft (اجرای JCO ، گربه گربه)
  • آزمایشگاه های Calvin PrewittJaf (اجرای JCO)
  • الکس کریچتون و جوئل دیسفر Fermyon (WASM-TOOLS ، WIT-BINDGEN و WASMTIME)

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا