I concur with other posters that M:N is a better foundation for runtime
performance if you want to scale to large number of tasks. Some "data
points" (more like anecdotes):
1. In my own personal experience, I implemented a coroutine system that
did M:N with expandable stacks precisely as Graydon outlined (linked
list of chunks at fixed positions in memory). At one point we did some
micro-benchmarks which suggested 1:1 threading wouldn't be so painful,
so we ported the system over---and ended up regretting that decision for
a long time, since it was very hard to "unport", and the overall system
was definitely slower and scaled much more poorly, despite the
micro-benchmarks.
2. Java may have a 1:1 model, but---in practice---there is a lot of
movement towards M:N. It's just that this M:N mapping is being done in
libraries, such as Doug Lea's Fork-Join scheduler work, as well as
projects like Kilim and others (not to mention the ever present thread
pools and executors, which are basically a primitive M:N setup). These
projects have the disadvantage, however, of lacking access to low-level
operations, which gives them an inherent efficiency gap. They can't
implement a chunked stack, for example.
3. In addition to Haskell, I believe that Erlang uses M:N scheduling.
The main downside of M:N as I see it is interaction with C code. This
IS a significant downside, to be sure. It's the reason that we tried to
port over to 1:1, as described above. The techniques Graydon described
(make a big chunk of space, limit callbacks when possible) are basically
what we were using before. They do address the problem, though they can
sometimes be a pain. There is also the challenge of implementing O/S
concepts like high vs low priority threads and so forth, if those prove
necessary.
Regarding the efficient implementation of yield points and the like, the
Capriccio project [1] discussed a number of techniques in a paper some
time back. The project seems to be dead at this point, unfortunately.
Still I think (as many others have said) that these costs are quite
minimal, especially in exchange for the scalability and control that you
get.
Niko
[1] http://capriccio.cs.berkeley.edu/
Sebastian Sylvan wrote:
2011/5/25 Rafael Ávila de Espíndola<respind...@mozilla.com>:
Of arguing that the absence of data motivates a particular assumption.
In this case it has to do with yield checking (which, incidentally, we
do have some data on from the work in other JITs, and it's seldom a cost
center).
Elsewhere you seem to be frustrated that in the absence of data to the
contrary, I'm promoting the assumption that M:N (even if it runs 1:1
much of the time) is a safer default than mandatory-1:1. I can't say for
certain which of those scenarios *will* need M:N and how badly it'll
hurt to be without; but I feel like mandatory-1:1 will paint ourselves
into a bunch of potential corners, as I tried to point out in the last
email. So I'm arguing the M:N stance is safer to start.
Or maybe you're not frustrated about that, or hadn't previously
considered those scenarios, and I am just reading frustration into the
argument. Did any of the points I raised in defense of *permitting* M:N
operation sound reasonable?
I still don't see where I made an accusation. If I did, sorry, it was not
the intention.
I am a bit frustrated that in the absence of data we are selecting the more
expensive option which is also the more expensive to backtrack and following
the examples of the least successful languages.
I'm somewhat unconvinced that spawning an OS thread for every task
should be considered the less expensive option. Easier to do, yes, but
that pariticular performance claim goes directly against my
performance intution, and could use some substantiation, IMO.
E.g. Haskell does M:N threads and it's much more efficient than OS
threads. I'd link you some microbenchmarks from the shootout game but
that website seems broken at the moment - IIRC on the benchmarks
measuring concurrency overhead, Haskell's M:N threading beat pretty
much everything else including C without breaking much of a sweat.
So, my current "gut instinct" (in the absence of data) is to favour
light weight tasks that map to (few) OS tasks, for performance
reasons. You seem to oppose that on performance grounds. I'm not sure
why our intuitions differ, but I don't think there's enough data to,
at this point, position the 1:1 option as the more higher performance
option. Did I miss some elaboration on why you think it is?
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev