WebAssembly Threads đã sẵn sàng để thử trong Chrome 70

Tính năng hỗ trợ luồng WebAssembly đã được phát hành trong Chrome 70 theo bản dùng thử theo nguyên gốc.

Alex Danilo

WebAssembly (Oncem) cho phép biên dịch mã được viết bằng C++ và các ngôn ngữ khác chạy trên web. Một tính năng rất hữu ích của ứng dụng gốc là khả năng sử dụng các luồng – cơ sở dữ liệu nguyên gốc để tính toán song song. Hầu hết các nhà phát triển C và C++ đều đã quen thuộc với pthreads, một API được chuẩn hoá để quản lý luồng trong một ứng dụng.

Nhóm cộng đồng WebAssembly đang nỗ lực đưa các luồng lên web để hỗ trợ các ứng dụng đa luồng thực sự. Là một phần của nỗ lực này, V8 đã triển khai tính năng hỗ trợ cần thiết cho các luồng trong công cụ WebAssembly, có sẵn thông qua Bản dùng thử theo nguyên gốc. Bản dùng thử theo nguyên gốc cho phép nhà phát triển thử nghiệm các tính năng web mới trước khi các tính năng đó được chuẩn hoá hoàn toàn. Điều này cho phép chúng tôi thu thập ý kiến phản hồi thực tế từ các nhà phát triển táo bạo. Đây là điều quan trọng để xác thực và cải thiện các tính năng mới.

Bản phát hành Chrome 70 hỗ trợ các luồng cho WebAssembly. Do đó, các nhà phát triển quan tâm nên bắt đầu sử dụng các luồng này và cho chúng tôi biết ý kiến phản hồi của họ.

Chuỗi cuộc trò chuyện? Còn Worker thì sao?

Các trình duyệt đã hỗ trợ tính năng tải song song thông qua Web Workers kể từ năm 2012 trong Chrome 4; trên thực tế, việc nghe các thuật ngữ như "trên luồng chính", v.v. là điều bình thường. Tuy nhiên, Trình chạy web không chia sẻ dữ liệu có thể thay đổi giữa chúng, thay vào đó dựa vào tính năng truyền tin nhắn để giao tiếp. Trên thực tế, Chrome phân bổ một công cụ V8 mới cho mỗi công cụ này (được gọi là công cụ tách biệt). Các lớp tách biệt không chia sẻ cả mã đã biên dịch lẫn đối tượng JavaScript, do đó, chúng không thể chia sẻ dữ liệu có thể thay đổi như pthread.

Mặt khác, luồng WebAssembly là các luồng có thể chia sẻ cùng một bộ nhớ Wasm. Việc lưu trữ cơ bản của bộ nhớ dùng chung được hoàn thành bằng một SharedArrayBuffer, một nguyên gốc JavaScript cho phép chia sẻ đồng thời nội dung của một ArrayBuffer duy nhất giữa các worker. Mỗi luồng WebAssembly chạy trong một Web Worker, nhưng bộ nhớ Wasm dùng chung của chúng cho phép chúng hoạt động giống như trên các nền tảng gốc. Tức là các ứng dụng sử dụng luồng Wasm chịu trách nhiệm quản lý quyền truy cập vào bộ nhớ dùng chung như trong mọi ứng dụng theo luồng truyền thống. Hiện có nhiều thư viện mã được viết bằng C hoặc C++ sử dụng pthreads và những thư viện đó có thể được biên dịch thành Wasm và chạy ở chế độ tạo luồng thực, cho phép nhiều lõi hoạt động đồng thời trên cùng một dữ liệu.

Ví dụ đơn giản

Dưới đây là ví dụ về một chương trình "C" đơn giản có sử dụng các luồng.

#include <pthread.h>
#include <stdio.h>

// Calculate Fibonacci numbers shared function
int fibonacci(int iterations) {
    int     val = 1;
    int     last = 0;

    if (iterations == 0) {
        return 0;
    }
    for (int i = 1; i < iterations; i++) {
        int     seq;

        seq = val + last;
        last = val;
        val = seq;
    }
    return val;
}
// Start function for the background thread
void *bg_func(void *arg) {
    int     *iter = (void *)arg;

    *iter = fibonacci(*iter);
    return arg;
}
// Foreground thread and main entry point
int main(int argc, char *argv[]) {
    int         fg_val = 54;
    int         bg_val = 42;
    pthread_t   bg_thread;

    // Create the background thread
    if (pthread_create(&bg_thread, NULL, bg_func, &bg_val)) {
        perror("Thread create failed");
        return 1;
    }
    // Calculate on the foreground thread
    fg_val = fibonacci(fg_val);
    // Wait for background thread to finish
    if (pthread_join(bg_thread, NULL)) {
        perror("Thread join failed");
        return 2;
    }
    // Show the result from background and foreground threads
    printf("Fib(42) is %d, Fib(6 * 9) is %d\n", bg_val, fg_val);

    return 0;
}

Đoạn mã đó bắt đầu bằng hàm main(). Hàm này khai báo 2 biến fg_valbg_val. Ngoài ra, còn có một hàm tên là fibonacci(), được gọi bởi cả hai luồng trong ví dụ này. Hàm main() tạo một luồng trong nền bằng cách sử dụng pthread_create() có nhiệm vụ là tính toán giá trị chuỗi số fibonacci tương ứng với giá trị của biến bg_val. Trong khi đó, hàm main() chạy trong luồng trên nền trước sẽ tính toán hàm này cho biến fg_val. Sau khi luồng trong nền chạy xong, kết quả sẽ được in ra.

Biên dịch để hỗ trợ luồng

Trước tiên, bạn nên cài đặt SDK mô phỏng, tốt nhất là phiên bản 1.38.11 trở lên. Để tạo mã mẫu có bật các luồng chạy trong trình duyệt, chúng ta cần truyền một số cờ bổ sung vào trình biên dịch emscripten emcc. Dòng lệnh của chúng tôi có dạng như sau:

emcc -O2 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -o test.js test.c

Đối số dòng lệnh "-s USE_PTHREADS=1" bật chế độ hỗ trợ phân luồng cho mô-đun WebAssembly được biên dịch và đối số "-s PTHREAD_POOL_SIZE=2" yêu cầu trình biên dịch tạo một nhóm gồm hai (2) luồng.

Khi chạy, chương trình sẽ tải mô-đun WebAssembly, tạo một Web Worker cho từng luồng trong nhóm luồng, chia sẻ mô-đun với từng trình thực thi, trong trường hợp này là 2 và các mô-đun đó sẽ được dùng mỗi khi có lệnh gọi đến pthread_create() được thực hiện. Mỗi worker sẽ tạo thực thể cho mô-đun Wasm bằng cùng một bộ nhớ, cho phép họ hợp tác. Các thay đổi mới nhất của V8 trong phiên bản 7.0 chia sẻ mã gốc được biên dịch của các mô-đun Wasm được truyền giữa các trình thực thi, cho phép các ứng dụng rất lớn có thể mở rộng quy mô cho nhiều trình thực thi. Lưu ý: Bạn cần đảm bảo kích thước nhóm luồng bằng với số lượng luồng tối đa mà ứng dụng của bạn cần. Nếu không, quá trình tạo luồng có thể không thành công. Đồng thời, nếu kích thước nhóm luồng quá lớn, bạn sẽ tạo ra các Trình chạy web không cần thiết và chỉ sử dụng bộ nhớ.

Cách dùng thử

Cách nhanh nhất để kiểm thử mô-đun WebAssembly là bật tính năng hỗ trợ luồng WebAssembly thử nghiệm trong Chrome 70 trở lên. Chuyển đến URL about://flags trong trình duyệt như sau:

Trang cờ Chrome

Tiếp theo, hãy tìm chế độ cài đặt luồng WebAssembly thử nghiệm như sau:

Cài đặt luồng WebAssembly

Thay đổi chế độ cài đặt thành Enabled (Bật) như bên dưới rồi khởi động lại trình duyệt.

Đã bật chế độ cài đặt luồng WebAssembly

Sau khi trình duyệt khởi động lại, chúng ta có thể thử tải mô-đun WebAssembly theo luồng với một trang HTML tối thiểu, chỉ chứa nội dung sau:

<!DOCTYPE html>
<html>
  <title>Threads test</title>
  <body>
    <script src="test.js"></script>
  </body>
</html>

Để dùng thử trang này, bạn cần chạy một loại máy chủ web và tải máy chủ đó từ trình duyệt của mình. Việc đó sẽ khiến mô-đun WebAssembly tải và chạy. Việc mở DevTools sẽ cho chúng ta thấy kết quả của lần chạy và bạn sẽ thấy một số nội dung như hình ảnh đầu ra bên dưới trong bảng điều khiển:

Kết quả trên bảng điều khiển từ chương trình fibonacci

Chương trình WebAssembly với các luồng đã được thực thi thành công! Bạn nên dùng thử ứng dụng theo luồng của riêng mình theo các bước nêu trên.

Thử nghiệm tại thực địa bằng Bản dùng thử theo nguyên gốc

Bạn có thể dùng thử luồng bằng cách bật cờ thử nghiệm trong trình duyệt cho mục đích phát triển. Tuy nhiên, nếu muốn kiểm thử ứng dụng trong trường, bạn có thể thực hiện với tính năng còn gọi là bản dùng thử theo nguyên gốc.

Bản dùng thử theo nguyên gốc cho phép bạn dùng thử các tính năng thử nghiệm với người dùng bằng cách lấy mã thông báo thử nghiệm liên kết với miền của bạn. Sau đó, bạn có thể triển khai ứng dụng và kỳ vọng ứng dụng đó hoạt động trong một trình duyệt có thể hỗ trợ tính năng mà bạn đang thử nghiệm (trong trường hợp này là Chrome 70 trở lên). Để lấy mã thông báo của riêng bạn nhằm chạy bản dùng thử theo nguyên gốc, hãy sử dụng biểu mẫu đăng ký tại đây.

Chúng tôi đã lưu trữ ví dụ đơn giản ở trên bằng mã thông báo dùng thử theo nguyên gốc, vì vậy bạn có thể tự mình dùng thử mà không cần tạo bất cứ thứ gì.

Nếu muốn biết 4 luồng chạy song song có thể làm gì cho nghệ thuật ASCII, bạn cũng phải xem bản minh hoạ này!

Gửi phản hồi cho chúng tôi

Luồng WebAssembly là một dữ liệu nguyên gốc mới cực kỳ hữu ích để chuyển các ứng dụng lên web. Hiện tại, bạn có thể chạy các ứng dụng và thư viện C và C++ yêu cầu hỗ trợ pthreads trong môi trường WebAssembly.

Chúng tôi đang tìm ý kiến phản hồi của các nhà phát triển dùng thử tính năng này vì tính năng sẽ giúp thông báo cho quá trình tiêu chuẩn hoá cũng như xác thực tính hữu ích của tính năng. Cách tốt nhất để gửi ý kiến phản hồi là báo cáo vấn đề và/hoặc tham gia vào quy trình tiêu chuẩn hoá trong Nhóm cộng đồng WebAssembly.