lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Fri, Aug 07, 2015 at 09:51:30AM -0400, Rena wrote:
<snip>
> I really hope a future Lua version will provide (or allow a module to
> provide in an unmodified Lua) true multithreading. With multi-core
> processors being so common now, not being able to make use of them is
> rather limiting. Even Python, the "batteries, charger and solar cells
> included" language, seems to have missed this boat - it provides
> "threading", but only one thread can actually run at a time (global
> interpreter state is locked while executing) and it doesn't sound like it'd
> be easy to fix without breaking other things.
<snip>
> The holy grail of course would be true parallel execution, using multiple
> CPU cores, within one Lua state. It's just unfortunate that threading is
> one of those annoying things that's extremely difficult to do correctly,
> but extremely easy to do in a way that seems to work but contains a subtle,
> critical flaw that only manifests in production at 16:53 on a Friday, just
> once, and then can't be reproduced until everyone has dismissed it as
> cosmic ray induced error and given up looking for the bug.

  If you were to design a new language today, he said, you would make it
  without mutable (changeable) objects, or with limited mutability.

  -- Guido on Python, discussing the GIL. See https://lwn.net/Articles/651967/

Shared, mutable memory and scalable multithreading don't mix. If you're
using a language (like Lua or Python) fundamentally based on mutable data
structures, you're going to do best with message passing. Trying to tweak
the language to be multi-thread safe will destroy performance all around.

Some groups (e.g. PyPy) have experimented with transactional memory, but the
amount of complexity needed (in amount of code, in number of
pipeline-stalling branches and atomic operations) to transparently give
transactional semantics to operations on complex primitive data structures
saps performance. It's not going to be much better, if at all, than message
passing. And it will effect performance even when you don't need those
semantics, which is most of the time. For example, it will dramatically
complicate the garbage collector, especially if you to preserve performance.
Lest we forget, the PUC team removed the generational collector, which
theretically should have given significantly better performance, because the
code complexity relative to the existing, simpler collector overwhelmed the
algorithmic gains.

But message passing is better for more reasons than just performance.

1) When you're dealing with languages with mutable data, bugs are easier to
introduce and more difficult to discover. This is compounded many fold when
you add in shared-memory parallelism. Message passing moves you toward the
ideal of immutable data, with concomitantly fewer bugs.

2) With message passing designs you can more easily move to multi-server
frameworks.

It's also a good idea to minimize mutability even when you're not
multithreading. RAII patterns reduce the complexity of code by reducing the
number of places and ways objects can mutate, thus reducing the number of
possible program states and number of failure paths.

Basically, you should strive for immutability all around. There's nothing
inelegant about message passing except in the most simplistic of scenarios.