story
Python as a language can support parallelism via threads, and CPython as an implementation can via multiprocessing, but those are both very low level abstractions; Raku has higher level abstractions which allow much more succinct expression of parallel operations.
sub foo ( Int \n where 1..100 ) {
# ___ start is a prefix operator that creates a Promise
# V
start { sleep n.rand; (1..n).pick }
}
my $result = foo(10);
say $result.status; # Planned
say await $result; # 6 (after a delay)
# this is nearly identical to foo above
sub bar ( Int \n where 1..100 ) {
Promise.in( n.rand ).then({ (1..n).pick })
}
(Note that `start` does not need a block unless you are grouping more than one statement as I have above.)There are combinators like `Promise.allof` and `Promise.anyof`.
You usually don't need to use `Promise.allof`, because you can use `await` on a list.
my @promises = Promise.in(1.rand) xx 10;
my @results = await @promises;
(Note that the left side of `xx` is _thunky_ so there are ten different Promises with ten different random wait times.)---
You should see the `react`/`supply` and `whenever` feature.
lliamander replied that Elixir does too and it's worth a look
To that, 7thaccount replied that Perl6 and Elixir fill different niches.
So far, it seems Perl6 fills a niche that requires scripting and first-class concurrency. My question then is: what is this niche that requires very solid concurrency but also scripting. In other words, what does Perl6 have in terms of concurrency that Python does not (given they are both scripting languages)?
I don't know of many instances where scripting and concurrency would be needed in the same application. But if you wanted to use single language both for scripting tasks and applications that require concurrency, then Raku or Elixir would work.
One instance I can actually think of, that would be specific to Erlang/Elixir, is if you have a long running service that you sometimes run batch jobs against (like importing data from a CSV). An Elixir script can hook directly into an Elixir/Erlang service and interact with it using message passing. It's a heck of a lot simpler than RMI, and avoids the need to expose new HTTP endpoints specifically for such tasks.
To which the answer is “not only does Python not have them, but with the GIL CPython couldn't do much with them even if the language had them.”
edit: that is, as far as I can tell, after a quick Google, it's not too different from Python's Thread object.
I agree the GIL is a problem but it's only an issue for CPU-bound problems. Is there really an important amount of CPU-bound work that is written in a scripting language? If it's CPU-bound, wouldn't you want to use something lower level?
-----
Python's concurrency model is good for waiting on network or disk I/O because of its GIL (Global Interpreter Lock): https://realpython.com/python-gil/#the-impact-on-multi-threa...
If your program is CPU bound the GIL will slow you down. I'm sure since the python ecosystem is quite vast there are ways around the GIL... but then you have to worry about every library you use not supporting "real" multi-threading, or (b)locking for no reason and shitting all over your efforts.
When I have a bit of Raku code that is too slow I complain (send a bug report) and then someone else figures out why the JIT isn't doing a better job and fixes it.
Then bingo-bango it ends up even faster than using NativeCall to call into the C code.
Of course there may be a delay before someone gets around to figuring it out; so in the meantime, NativeCall is actually very easy to use.
---
I would like to note that someone wrote Perl6/Raku code and the equivalent C/C++ code. They reported that the Perl6/Raku code was faster. (It was before Raku was brought up as an alias/name.)
I'm fairly sure that the reason the C/C++ code was slower is that it copied strings around rather than using pointers and indexes into other strings like MoarVM does.
I actually love doing CPU bound work in Groovy which is usually described as a scripting language. But it gets converted straight to java byte code which is JIT'd and ends up as machine code. It only takes a few static typed hints here and there and it runs in the same league as C++ implementations. And it gets Java's excellent concurrency support for free.
I'm personally with you. I also don't tend to think object boxing is really the performance bottleneck for most applications, and if/when it is, likely the other requirements should've already ruled out using one (a scripting language).
It's like writing Nifs for Elixir, yeah sure you _can_, they have their purpose, but you could also just write another application to do that one thing and like you said, use IPC.
So in summary, we agree with each other, here's to:
the right tool for the job!
Hear, hear!