I also don't agree that 10ms is ridiculous. That's barely any time at all. That's less than a frame, at 60Hz. And, how many interpreter instances are you going to start up? Surely, no more instances than you have cores; that means, worst-case scenario if you have a ryzen threadripper or a maxed-out POWER9 (both have 96 cores), a second. For most people, it's going to take under half a second; considering most programs take tens of seconds to start up, I think that's fine.
Not to mention that if you have 'complex initialization code', that's going to take a long time regardless of language; what we're testing the the language core baseline startup time.
And the number of interpreters you spawn isn't a function of cores either. It depends entirely what you're doing, and nobody was talking about parallel execution. If you run a bunch of Python scripts in sequence you'll multiply the startup overhead...
I guess we'll just have to disagree on 10ms being ridiculous for a program that does nothing. To me it is. And half a second is orders of magnitude more so.
P.S. All of this is my timing on a pretty darn fast CPU. Try running on a more typical laptop CPU, switching to battery, and you'll get even worse timing.
And yeah, I have only a crappy laptop and your benchmark takes more like 50ms/spawn for me. Which I still think is reasonable because there's no reason to make a new interpreter state for ever script.
For an embedded application, of course you'd try to keep the interpreter state if it's possible. Sometimes you can't because of global state changes; sometimes you can. And sometimes, even with a single interpreter, the rest of the C++ program is fast enough that the embedded Python initialization time would dominate its running time, rendering the standalone vs. embedded distinction moot.
In any case... all you're doing is amortizing slow startup cost over the lifetime of the program. The startup is still slow. You were wondering "how" the startup is slow, so I wrote you benchmarks and ran them to illustrate. If what you really wanted to argue was that startup time is irrelevant, maybe you should say that instead of asking "how is startup slow" and making me spend my time writing a benchmark for something you don't care about.
And I did give you an example of Python that doesn't import anything, and as you can see (and could have easily tested yourself) it was still a lot slower...
Now compare with Lua:
$ python3 -c "import sys, timeit; n = 10; print('%.2f ms/spawn' % (1000 * timeit.timeit('subprocess.call([%r, %r], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL)' % ('lua', '-'), 'import subprocess', number=n) / n))"
1.09 ms/spawn
NewLisp: $ python3 -c "import sys, timeit; n = 10; print('%.2f ms/spawn' % (1000 * timeit.timeit('subprocess.call([%r, %r], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL)' % ('newlisp', '-'), 'import subprocess', number=n) / n))"
1.25 ms/spawn python3 -S
To bypass unnecessary startup stuff.
Now try importing some stuff, and also testing a little more thoroughly...
For reference on Windows, here's PHP, taking half the time to start up: Now consider that you'll generally be doing a LOT more on initialization than just importing these packages, a lot of packages end up being extremely heavyweight, and very likely you'll be calling Python several times in a row... it can easily waste seconds on startup, even on Linux.