wasm-bindgen-rayon icon indicating copy to clipboard operation
wasm-bindgen-rayon copied to clipboard

Slightly confused about initialization directions

Open felipellrocha opened this issue 2 years ago • 7 comments

You must instantiate the main JS+Wasm in a dedicated Worker to avoid blocking the main thread - that is, don't mix UI and Rayon code together. Instead, use a library like Comlink or a custom glue code to expose required wasm-bindgen methods to the main thread, and do the UI work from there.

You'll need to invoke [the initThreadPool function] it right after instantiating your module on the main thread in order to prepare the threadpool before calling into actual library functions:

Which is it? :)

felipellrocha avatar Jun 16 '22 01:06 felipellrocha

See https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/issues/18#issuecomment-960949808 for deeper explanation:

Right, the wording there could certainly be improved. It's hard to convey difference between "main thread" as in "main thread from PoV of Rust code" vs "main thread" as in "browser main thread used for UI work".

What that comment meant is that init & initThreadPool need to be invoked from main thread from Rust PoV, even though it actually lives in the worker as per caveats.

It might be helpful to also look at the demo code which invokes those functions in a worker file: https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/5f54573052ea70986e1d23d3ebe876702c671335/demo/wasm-worker.js#L31-L32

I admit it's confusing and open to better rewording PRs.

RReverser avatar Jun 16 '22 01:06 RReverser

See https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/issues/18#issuecomment-960949808 for deeper explanation:

@RReverser for me this is not working :( Js fails on await multiThread.initThreadPool(navigator.hardwareConcurrency); with

Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'Worker': #<Memory> could not be cloned.

ceikit avatar Aug 24 '22 16:08 ceikit

Did you build with all required flags from README? Most likely, you're missing +atomics and company, as that error indicates a non-shared memory.

RReverser avatar Aug 25 '22 21:08 RReverser

@RReverser I run

RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals' && rustup run nightly-2022-03-14 wasm-pack build --target web --out-dir pkg

and build the pkg successfully but after installing it I get the same issue.

Changing to nightly-2022-04-07 does not help

ceikit avatar Aug 26 '22 22:08 ceikit

That is weird. Are you running in a browser that supports Wasm threads? (e.g. if you're on older Safari, it might be not available)

RReverser avatar Aug 27 '22 12:08 RReverser

@RReverser

For context, I've implemented a genetic algorithm in Rust and would like to run it in wasm on the browser. This works well without multithread, however as the computation it's fairly expensive I've used Rayon for parallelism (that's were wasm-bindgen-rayon comes in play.

Running on Chrome.

This is my wasm-worker.js

import { threads } from 'wasm-feature-detect';
import * as Comlink from 'comlink';

// Wrap wasm-bindgen exports (the `run_ga_wasm` function) to add time measurement.
function wrapExports({ run_ga_wasm }) {
    return ({ run_data, data }) => {
        console.log("Nsdsadsadsadasdasdsa");
        const start = performance.now();
        const dd = run_ga_wasm(run_data, data);
        const time = performance.now() - start;
        return {
            // Little perf boost to transfer data to the main thread w/o copying.
            dd: Comlink.transfer(dd, [dd.buffer]),
            time
        };
    };
}


async function initHandlers() {
    const startThread = async () => {
        const multiThread = await import('fantaga');
        await multiThread.default();
        console.log("NN", navigator.hardwareConcurrency);
        await multiThread.initThreadPool(navigator.hardwareConcurrency);  <--- fails here 
        return wrapExports(multiThread);
    }

    let multiThreadStarted = await startThread();

    return Comlink.proxy({
        multiThreadStarted
      });
    // return Comlink.proxy( multiThreadStarted );
}


Comlink.expose({
    handlers: initHandlers()
});

ceikit avatar Aug 27 '22 15:08 ceikit

It's called in App.tsx like this :

[...]
import * as Comlink from 'comlink';

function App(this: any) {

  const [sss, setCard] = useState<Number>();
  const [wasm_init, setWasmInit] = useState<number>();
  const [team, setTeam] = useState<Array<Player>>();
  /// need to 'start' the wasm module with init()
  /// it is async so we need to wait 
  useEffect(() => {
    const fetchData = async () => {

      let handlers = await Comlink.wrap(
        new Worker(new URL('./wasm-worker.js', import.meta.url), {
          type: 'module'
        })
      );

      console.log(handlers);

      setCard(3);
    };

    fetchData();

  }, [])

[...]

Also I noticed I cannot do . handlers (as in the example) on the above Comlink.wrap, I can just do image

not sure that's an issue

ceikit avatar Aug 27 '22 15:08 ceikit

Latest version of wasm-bindgen-rayon allows to use Rayon directly from the main thread, without extra Worker and Comlink.

RReverser avatar Jan 17 '24 20:01 RReverser