Workers threads spawn a new JS VM( which implies a new GC) for each worker! We tried it and the gains from parallelism stopped when there were half as many workers as CPUs.
They do create a new VM isolate. That’s a cost your workload will need to exceed before you get much if any benefit.
As far as thread count, my default guidance is 50% of cores if your CPU has SMT/hyper threading, coreCount - 2 otherwise.
Those numbers can go higher depending on how much of your workload is CPU-heavy. If you have an even mix of compute and IO, for example, your threads will frequently be idle/less contentious (same principle as the single threaded event loop).
And if your workload is a queue of short lived, isolated steps, I also recommend pre-spawning idle threads (potentially well beyond that active maximum). Pre-warming those isolates can help as well, or isolating with vm APIs (eg SourceTextModule) instead.
As with, well, everything: your mileage may vary, it depends on your actual bottlenecks and constraints, as well as your tolerance for tuning.