I always thought that the only benefit of using dash instead of bash was that dash was smaller, and therefore many instances of dash would start faster at boot time.
But I have done some research, and found some people migrating all their scripts to dash in the hope they would run faster, and I also found this in the article DashAsBinSh in the Ubuntu Wiki:
The major reason to switch the default shell was efficiency. bash is an excellent full-featured shell appropriate for interactive use; indeed, it is still the default login shell. However, it is rather large and slow to start up and operate by comparison with dash.
Nowadays I’ve been using lots of bash scripts for many things on my system, and my problem is that I have a particular script that I’m running continuously 24/7, that spawns around 200 children, which together heat my computer 10°C more than in normal usage.
It is a rather large script with lots of bashisms, so porting them to POSIX or some other shell would be very time consuming (and POSIX doesn’t really matter for personal use), but it would be worth if I could reduce some of this CPU usage. I know there are also other things to consider, like calling an external binary like sed for a simple bashism like ${foo/bar}, or grep instead of =~.
TL;DR is really bash slower to start up and operate in comparison with dash? Are there other Unix shells which are more efficient than bash?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
SHELL SEQ:
Probably a useful means of bench-marking a shell’s performance is to do a lot of very small, simple evaluations repetitively. It is important, I think, not just to loop, but to loop over input, because a shell needs to read <&0.
I thought this would complement the tests @cuonglm already posted because it demonstrates a single shell process’s performance once invoked, as opposed to his which demonstrates how quickly a shell process loads when invoked. In this way, between us, we cover both sides of the coin.
Here’s a function to facilitate the demo:
sh_bench() ( #dont copy+paste comments
o=-c sh=$(command -v "$1") ; shift #get shell $PATH; toss $1
[ -z "${sh##*busybox}" ] && o='ash -c' #cause its weird
set -- "$sh" $o "'$(cat <&3)'" -- "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="674327">[email protected]</a>" #<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="082c48">[email protected]</a> = invoke $shell
time env - "$sh" $o "while echo; do echo; done|$*" #time (env - sh|sh) AC/DC
) 3<<-SCRIPT
#Everything from here down is run by the different shells
i="${2:-1}" l="${1:-100}" d="${3:-
}"; set -- "$((n=$n${n:++$i}))$d" #prep loop; prep eval
set -- $1$1$1$1$1$1$1$1$1$1 #yup
while read m #iterate on input
do [ $(($i*50+${n:=-$i})) -gt "$(($l-$i))" ] || #eval ok?
eval echo -n ""$1$1$1$1$1"" #yay!
[ $((n=$i+$n)) -gt "$(($l-$i))" ] && #end game?
echo "$n" && exit #and EXIT
echo -n "$n$d" #damn - maybe next time
done #done
#END
SCRIPT #end heredoc
It either increments a variable once per newline read or, as a slight-optimization, if it can, it increments 50 times per newline read. Every time the variable is incremented it is printed to stdout. It behaves a lot like a sort of seq cross nl.
And just to make it very clear what it does – here’s some truncated set -x; output after inserting it just before time in the function above:
time env - /usr/bin/busybox ash -c '
while echo; do echo; done |
/usr/bin/busybox ash -c '"'$(
cat <&3
)'"' -- 20 5 busybox'
So each shell is first called like:
env - $shell -c "while echo; do echo; done |..."
…to generate the input that it will need to loop over when it reads in 3<<SCRIPT – or when cat does, anyway. And on the other side of that |pipe it calls itself again like:
"...| $shell -c '$(cat <<SCRIPT)' -- $args"
So aside from the initial call to env (because cat is actually called in the previous line); no other processes are invoked from the time it is called until it exits. At least, I hope that’s true.
Before the numbers…
I should make some notes on portability.
-
poshdoesn’t like$((n=n+1))and insists on$((n=$n+1)) -
mkshdoesn’t have aprintfbuiltin in most cases. Earlier tests had it lagging a great deal – it was invoking/usr/bin/printffor every run. Hence theecho -nabove. - maybe more as I remember it…
Anyway, to the numbers:
for sh in dash busybox posh ksh mksh zsh bash
do sh_bench $sh 20 5 $sh 2>/dev/null
sh_bench $sh 500000 | wc -l
echo ; done
That’ll get ’em all in one go…
0dash5dash10dash15dash20 real 0m0.909s user 0m0.897s sys 0m0.070s 500001 0busybox5busybox10busybox15busybox20 real 0m1.809s user 0m1.787s sys 0m0.107s 500001 0posh5posh10posh15posh20 real 0m2.010s user 0m2.060s sys 0m0.067s 500001 0ksh5ksh10ksh15ksh20 real 0m2.019s user 0m1.970s sys 0m0.047s 500001 0mksh5mksh10mksh15mksh20 real 0m2.287s user 0m2.340s sys 0m0.073s 500001 0zsh5zsh10zsh15zsh20 real 0m2.648s user 0m2.223s sys 0m0.423s 500001 0bash5bash10bash15bash20 real 0m3.966s user 0m3.907s sys 0m0.213s 500001
ARBITRARY = MAYBE OK?
Still, this is a rather arbitrary test, but it does test reading input, arithmetic evaluation, and variable expansion. Maybe not comprehensive, but possibly near to there.
EDIT by Teresa e Junior: @mikeserv and I have done many other tests (see our chat for details), and we found the results could be summarized like this:
- If you need speed, go definitely with dash, it is much faster than any other shell and about 4x faster than bash.
- While busybox‘s shell can be much slower than dash, in some tests it could be faster, because it has many of its own userland utilities, like
grep,sed,sort, etc., which don’t have as many features as the commonly used GNU utilities, but can get the work done as much. - If speed is not everything you care about, ksh (or ksh93) can be considered the best compromisse between speed and features. It’s speed compares to the smaller mksh, which is way faster than bash, and it has also some unique features, like floating point arithmetic.
- Although bash is famous for its simplicity, stability, and functionality, it was the slowest of all shells in the majority of our tests, and by a large margin.
Method 2
Let do a benchmark.
With bash:
$ strace -cf bash -c 'for i in $(seq 1 1000); do bash -c ":"; done' % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 99.12 0.376044 188 2004 1002 wait4 0.74 0.002805 3 1002 clone 0.03 0.000130 0 4037 read 0.03 0.000119 0 15026 rt_sigprocmask 0.03 0.000096 0 15040 6017 stat 0.01 0.000055 0 8011 open 0.01 0.000024 0 5013 getegid 0.01 0.000021 0 16027 rt_sigaction 0.00 0.000017 0 9020 5008 access 0.00 0.000014 0 1001 1001 getpeername 0.00 0.000013 0 1001 getpgrp 0.00 0.000012 0 5013 geteuid 0.00 0.000011 0 15025 mmap 0.00 0.000011 0 1002 rt_sigreturn 0.00 0.000000 0 1 write 0.00 0.000000 0 8017 close 0.00 0.000000 0 7011 fstat 0.00 0.000000 0 8012 mprotect 0.00 0.000000 0 2004 munmap 0.00 0.000000 0 18049 brk 0.00 0.000000 0 1 pipe 0.00 0.000000 0 1 dup2 0.00 0.000000 0 1001 getpid 0.00 0.000000 0 1002 execve 0.00 0.000000 0 1001 uname 0.00 0.000000 0 1001 getrlimit 0.00 0.000000 0 5013 getuid 0.00 0.000000 0 5013 getgid 0.00 0.000000 0 1001 getppid 0.00 0.000000 0 1002 arch_prctl 0.00 0.000000 0 1001 time ------ ----------- ----------- --------- --------- ---------------- 100.00 0.379372 158353 13028 total
With dash:
$ strace -cf bash -c 'for i in $(seq 1 1000); do dash -c ":"; done' % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 73.88 0.008543 4 2004 1002 wait4 25.35 0.002932 3 1002 clone 0.62 0.000072 0 9026 rt_sigprocmask 0.10 0.000011 0 1002 rt_sigreturn 0.05 0.000006 0 15027 rt_sigaction 0.00 0.000000 0 1037 read 0.00 0.000000 0 1 write 0.00 0.000000 0 2011 open 0.00 0.000000 0 2017 close 0.00 0.000000 0 2040 17 stat 0.00 0.000000 0 2011 fstat 0.00 0.000000 0 8025 mmap 0.00 0.000000 0 3012 mprotect 0.00 0.000000 0 1004 munmap 0.00 0.000000 0 3049 brk 0.00 0.000000 0 3020 3008 access 0.00 0.000000 0 1 pipe 0.00 0.000000 0 1 dup2 0.00 0.000000 0 1001 getpid 0.00 0.000000 0 1 1 getpeername 0.00 0.000000 0 1002 execve 0.00 0.000000 0 1 uname 0.00 0.000000 0 1 getrlimit 0.00 0.000000 0 13 getuid 0.00 0.000000 0 13 getgid 0.00 0.000000 0 1013 geteuid 0.00 0.000000 0 13 getegid 0.00 0.000000 0 1001 getppid 0.00 0.000000 0 1 getpgrp 0.00 0.000000 0 1002 arch_prctl 0.00 0.000000 0 1 time ------ ----------- ----------- --------- --------- ---------------- 100.00 0.011564 60353 4028 total
Each iteration only start a shell and do nothing with no-op operator – colon, then quit.
As the result show, dash is extremely faster than bash at startup. dash is smaller, and depend on less shared library than bash:
$ du -s /bin/bash
956 /bin/bash
$ du -s /bin/dash
108 /bin/dash
$ ldd /bin/bash
linux-vdso.so.1 => (0x00007fffc7947000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f5a8110d000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5a80f09000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5a80b7d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5a81352000)
$ ldd /bin/dash
linux-vdso.so.1 => (0x00007fff56e5a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb24844c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb2487f3000)
This is about startup time, how about operate. Let do another benchmark:
$ time dash -c 'for i in $(seq 1 1000000);do [ 1 = 1 ];done' real 0m2.684s user 0m2.728s sys 0m0.100s $ time bash -c 'for i in $(seq 1 1000000);do [ 1 = 1 ];done' real 0m6.996s user 0m6.820s sys 0m0.376s
With simple test 1 = 1, dash still much faster than bash.
Method 3
Here’s some startup timings of various shells in a certified UNIX (Mac OS X 10.10.3). I rewrote the test to use tcsh to control the loops so that the shell being tested was not the one controlling the loops. For each shell the loop is executed five times prior to timing, to ensure that the shell executable and the scripts are in cache.
As you can see, there’s no clear-cut winner, but there’s one definitive loser. Anyhow, bash 4 is distinctly slower than bash 3. Dash performs well, but given that ksh93 is now open-source, there’s no real reason not to use it for everything (apologies if I misunderstand any licensing niceties): ksh93 is fast, solid, and a de-facto standard in UNIX-land (if not in GNU/Linux-land); it provides a superset of the POSIX shell functionality (as far as I understand, the POSIX shell was based on ksh88); it is equal to bash as an interactive shell, though lagging compared to tcsh. And the loser is of course zsh.
/bin/bash is v3.2.57(1)
/usr/local/bin/bash is v4.3.33(1)
dash is v0.5.8
ksh is v93u+
mksh is vR50f
pdksh is v5.2.14
/opt/heirloom/5bin/sh is from SysV
yash is v2.37
zsh is v5.0.5
% cat driver.csh
#!/bin/tcsh
foreach s ( $* )
echo
echo "$s"
foreach i ( `seq 1 5` )
./simple_loop.csh "$s"
end
/usr/bin/time -p ./simple_loop.csh "$s"
end
% cat simple_loop.csh
#!/bin/tcsh
set shell = `which ${1}`
foreach i ( `seq 1 1000` )
${shell} -c ":"
end
% ./driver.csh /bin/bash /usr/local/bin/bash dash ksh mksh pdksh /opt/heirloom/5bin/sh yash zsh
/bin/bash
real 4.21
user 1.44
sys 1.94
/usr/local/bin/bash
real 5.45
user 1.44
sys 1.98
dash
real 3.28
user 0.85
sys 1.11
ksh
real 3.48
user 1.35
sys 1.68
mksh
real 3.38
user 0.94
sys 1.14
pdksh
real 3.56
user 0.96
sys 1.17
/opt/heirloom/5bin/sh
real 3.46
user 0.92
sys 1.11
yash
real 3.97
user 1.08
sys 1.44
zsh
real 10.88
user 3.02
sys 5.80
Method 4
subshell benchmark is for sh/dash :
time ./sh.sh --> real 0m12.382s time ./dash.sh --> real 0m12.459s time ./bash.sh --> real 0m48.913s (Cannot allocate memory) K=$( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( $( exit ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )
Method 5
There are too many unfair test cases in many answers here. If test two shells then use the correct syntax for each of them. And in bash doublebrackets are much faster and more reliable than singlebrackets, so there is a much less speed difference at all. Also use optimized bashisms and then these speed differences are more less too. On my system bash runs like hell, with heavy use of bashisms. And posix equivalents in dash are slower here. This is not correct that dash is always multiple times faster than bash. Really it is pretty unfair to compare posix command lines in both, who dash can always be the fastest. In my view posix is heavy outdated. And in terms of compatibility, it is really hard to found relevant systems nowdays, they didn’t use a bash shell.
A good comparison is: to use the best possible command line in each shell, to finish a specific job. Not only exactly the same command line, when only one shell really has an advantage here. Comparisons like this are unreliable and didn’t show the real performance of the competitors. I see at my every day job, which shell is faster in many use cases.
For example, to replace all a characters in string with b characters, in bash you can write "${varname//a/b}" while in dash you have to call external tool like this: "$(echo "$varname" | sed 's/a/b/g')". If you have to repeat it few hundred times – using bashism can give you 2x speedup.
Method 6
Not all performance problems are efficiency problems, just the majority of them are, in contrast to reasonably efficient naive problems which require algorithmic solutions. If we were to fix one or the other in totality, more times than not the most efficient solution has the best performance.
Nobody can tell you the proper path to correcting the problem, but there is one specific efficiency problem POSIX shell can solve, which is the reason all the startup scripts were ported from Bash to Dash.
If you are experiencing performance problems because of large numbers of scripts starting-up at the same time, but they are all fairly reasonably efficient each on their own, then porting them all to POSIX shell is a preferable solution.
However I’d likely first double check to make sure you actually must be spawning so many processes at once, and that the specific part of the script cannot be re-written differently. You don’t mention if the 200 spawned children processes are other scripts, it might be possible to just port them instead of the larger parent script.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0