
PyPy: Transactional Memory (II) - megaman821
http://morepypy.blogspot.com/2012/01/transactional-memory-ii.html
======
lnanek
It's kind of funny how specific people's technology experience is becoming. He
considers separate processes unworkable, but it wouldn't bother me in the
slightest. Most code I've ever written was web server code with the only
serious runtime changing state in the DB anyway, so the the processes wouldn't
ever talk to each other anyway, just to the DB. Then he claims this is a whole
new set of problems and technology, but it sounds very similar to whenever I
work on a SOA setup. There your technology sometimes supports transaction
context across web service calls or it doesn't. So when it does, your web
service calls during your transaction can be rolled back when you rollback,
and when it doesn't you need specific calls out for roll back purposes or you
need to buffer until the end or break things up into reversible parts. Doesn't
sound that different from his concerns about calling out of the process into
the system and having to buffer if the system doesn't have a transaction
context.

~~~
fijal
Separate processes is completely unworkable for the kind of work armin has in
mind. Web servers are very specific - there is very little data shared between
processes, because web is mostly stateless and the entire state can be encoded
in SQL database (typically). However anything that requires some complex
interprocess communication is essentially unworkable. You need to serialize
and deserialize your data into wire-level protocols, which is often
prohibitively expensive, even when you can get it to work.

~~~
chubot
Honest question: what kind of work is that?

The more I think of it, the more I think that "high concurrency with local
state on one machine" is a use case that is not going to get more popular in
the future.

I believe a big part of the uptick in interest in concurrency is an uptick in
the use of distributed systems. With distributed systems, all your
authoritative state is stored outside the process anyway (at least if you want
it to be fault tolerant, which you do if you need it to be of any significant
size).

And of course once you have more than one machine you must deal with
serialization. Also, I'm not sure what the kind of work there is where
"serialization is prohibitively expensive" but Python is still a natural
choice.

~~~
fijal
well. it's not entirely true, if distributed systems were the future, we would
never see multi-core systems at all, there are still tasks that are _much_
easier to do if you have them done on a single shared-memory system then
distributed. I don't think they're necesarilly less complex, they just don't
deal with any sort of "big data". pypy's translation toolchain is one of those
problems, but I can see a lot of situations where a large mostly-read-only set
is necessary to be accessible all the time.

regarding "Python is still a natural choice" - don't confuse python as a
language and python (CPython) as interpreter. You would not use CPython for
any performance-critical tasks probably, at least not without spending
significant time rewriting pieces to C, but PyPy is quite usable in some
scenarios and the list is only to grow.

~~~
chubot
> there are still tasks that are much easier to do if you have them done on a
> single shared-memory system then distributed.

Such as...? A lot of the big users of cray-type systems were for scientific
uses. AFAIK a lot of them are seriously looking at cloud or commodity-type
clusters as the problems get bigger.

Anyway I am curious if PyPy is aiming at some specific problem that I don't
know about. For "web stuff", I think what is proposed is perhaps overly
complicated.

If you want a large read-only set of data to fit on one machine and need high
performance, Java, Python and the like aren't great choices because they don't
give you much control over the memory layout. Python is probably better
because you could write a C extension. But PyPy itself is not optimized for
memory size (in fact I think it uses more memory to get speed).

------
lubutu
What surprised me most was discovering that Intel's upcoming Haswell
microarchitecture may include Hardware Transactional Memory. That's pretty
exciting!

~~~
mark_h
I hadn't heard that, thanks. That's kind of a full-circle moment then, given
that transactional memory started out as a hardware proposal!

------
sanxiyn
As I understand, they seem to say TM failed because it was considered as an
alternative to threads and events, so they propose to do events+TM.

That is, one big problem with TM is I/O, like doing network read and write.
But if you are already writing event-driven programs, you return to event loop
whenever you do network read and write, and at that point TM implementation
can do smart things. If TM is sold as "write threads without locks" this can't
work, but if TM is "write events but with more parallelism" this seems
possible.

Actually I am quite surprised that this model was not heavily investigated
already.

~~~
Peaker
TM does work well in Haskell, though, where constraining IO effects during a
transaction is simple.

------
sbov
I've done similar in a personal project before: a multiplayer text game (a
MUD). In general, in these games, the actions you and creatures perform only
interact with things that are locationally close to them. Each location
belongs to an "area" - so each "area" had a thread to execute actions. There
were also world "actions" that had to execute in isolation, but those were
much rarer.

That said, a lot of people seem to dislike threads. The problem isn't with
threads, but rather having to shoehorn every attempt to parallelize your
program into a threaded model. I would feel similar ire if I had to shoehorn
every attempt to parallelize my program into an event model.

Threads are a way you can reason about and simplify your program. I've written
programs where threads make the program easier to reason about rather than
harder. Because of this, telling me your method is better than threads makes
no sense to me - for what class of problems?

~~~
sanxiyn
> I've written programs where threads make the program easier to reason about
> rather than harder.

I want to hear about this.

~~~
sbov
The one that comes to mind in particular was something that sent email. We
wanted to limit emails being sent per email server to each ISP.

We went with: queue per ISP for emails to send out, then each server that
could send email to that ISP had its own thread. Each thread would take X
emails out of the queue every 10 seconds, send them, then sleep for any
leftover time - or not if there isn't any.

Most of the time is spent sleeping or on I/O - the point of threads wasn't for
CPU usage, it was because it made everything so simple to implement. The only
synchronization issues were taking emails out of the queue and putting them
back somewhere if they failed to send.

All of the logic for each thread in its main loop read like a normal,
sequential program. I guess you could call this an embarrassingly easy
problem, but part of why it's so easy is it maps so easily to threads.

------
radarsat1
I actually kind of like the GIL. It allows me to write threaded code in a
"lazy" way sometimes, when I don't want to take the effort to do it properly.
(e.g. implementing a message queue using a simple list, using a global bool or
int as a state flag.) Even though it's not using the correct structures for
these things, it sometimes allows to prototype a simple threaded approach
quickly, and at least be sure it won't cause weird clashes in the interpreter.
When I want to later port it to a proper solution, I'll switch to the
multiprocess model which forces you to use queues and other IPC mechanisms
instead of shared data structures-- this is more effort, but usually worth it,
if not for efficiency then for robustness. But for one-off scripts and little
proofs of concept it can be nice to just carefully share some variables and
know with some assurance that you're not going to break anything in the run-
time. That's not to say that transactional memory wouldn't be welcome, but
sometimes the GIL allows a certain pragmatism in a prototyping scenario.

In Python, threads are "enough" to implement event-based concurrency, as well
as asynchronous I/O and calling out to long-running C functions for number
crunching.

Beyond that, the main reason to remove the GIL and allow true multicore
parallelism is purely for efficiency reasons. The catch is, if I'm serious
about efficiency, I probably won't be using Python. Or at least porting only
my CPU-intensive functions to C.

Of course, if PyPy eventually provides Java-like speeds, maybe it makes sense
to go this route, as Python could start to be depended on for efficiency, so
the gains of true parallelism would be visible. But removing the GIL from
CPython seems kind of pointless, since the interpreter has so much overhead
regardless.

~~~
munin
you're getting lucky. as I understand it, the GIL just protects certain pieces
of interpreter state. you still need to lock to get correct behavior from your
code. the presence of the GIL doesn't remove the need to lock your data
structures and each thread created with the threading stdlib is actually a
native thread on your platform.

~~~
dripton
Yep. The GIL means that individual Python bytecode operations are atomic, and
so by extension single Python statements that translate to individual bytecode
instructions can be treated as atomic (if you don't care about portability to
alternate Python implementations that lack a GIL). But complicated Python
statements that translate into multiple bytecode instructions (like
dict.setdefault) can't. And, of course, neither can sequences of multiple
statements. So you still need locks for most cases where you mutate objects
that are shared across threads.

~~~
radarsat1
Ah yes, that's a good point. I wouldn't go as far as to say I'm just getting
lucky though, as I do tend to reserve my lazy bad practices to very simple
cases. But I would never use such code in production anyways.

------
simon_weber
The link to the previous entry is broken. Here it is:
[http://morepypy.blogspot.com/2011/06/global-interpreter-
lock...](http://morepypy.blogspot.com/2011/06/global-interpreter-lock-or-how-
to-kill.html)

