global interpreter lock

M

Michael Sparks

Paul said:
Well, ok, the Python equivalent would be wrapping every shareable
object in its own thread, that communicates with other threads through
Queues. This is how some Pythonistas suggest writing practically all
multi-threaded Python code. It does a reasonable job of avoiding
synchronization headaches and it's not that hard to code that way.

But I think to do it on Erlang's scale, Python needs user-level
microthreads and not just OS threads.

You've just described Kamaelia* BTW, except substitute micro-thread
with generator :) (Also we call the queues outboxes and inboxes, and
the combination of a generator in a class with inboxes and outboxes
components)
* http://kamaelia.sf.net/

For those who really want threads as well, theres a threaded component based
class that uses Queues instead :)

Best Regards,


Michael.
 
B

Bryan Olson

Mike said:
> Bryan Olson writes:
>
>
> In that case, the simpler model isn't necessarily getting the job
> done. I purposely didn't refine the word "job" just so this would be
> the case.

I didn't ask about any particular case. You stated a general
rule you follow, and I think that rule is nuts.

>
> I own too many orphans to ever confuse popularity with technical
> superiority.

The issue here is whether to confuse reality with what one might
wish reality to be.
> I've learned how to use threads, and done some
> non-trivial thread proramming, and hope to never repeat that
> experience. It was the second most difficult programming task I've
> ever attempted(*).

Great -- lets see it! Can you point out what parts were so
hard? How would you have solved the same problems without
threads?

> As I said above, the real problem isn't threads per
> se, it's that the model for programming them in popular languages is
> still primitive. So far, to achieve the non-repitition goal, I've used
> async I/O, restricted my use of real threads in popular languages to
> trivial cases, and started using servers so someone else gets tod eal
> with these issues.

Then maybe we should listen to those other people. Is there a
successful single-line-of-execution async-I/O based server that
provides a service as sophisticated as the modern relational-
database engines? Why do you think that is?
 
M

Mike Meyer

Bryan Olson said:
I didn't ask about any particular case. You stated a general
rule you follow, and I think that rule is nuts.

You're entitled to write code as complex and unmanagable as you
wish. Me, I'll stick with the simplest thing that solve the problem.
The issue here is whether to confuse reality with what one might
wish reality to be.

Let's see. Reality is that writing correct programs is hard. Writing
correct programs that use concurrency is even harder, because of the
exponential explosion of the order that operations can happen
in. Personally, I'm willing to use anything I can find that makes
those tasks easier.
Great -- lets see it! Can you point out what parts were so
hard? How would you have solved the same problems without
threads?

Google for "aws amiga web server". Somebody is liable to still have
the source around. The hard part was dealing with the making sure that
every sequence of operations that actually happened was correct, of
course. The web server I wrote after that used async i/o, thus
avoiding the problem completely.
Then maybe we should listen to those other people.

Yes, we probably should. I do. The problem is, the designers of
popular languages apparently don't, so I'm stuck with lousy tools like
thread libraries (meaning you get no compile-time help in avoiding the
problems that plague concurrent programs) and Java's pseudo-monitors.
Is there a successful single-line-of-execution async-I/O based
server that provides a service as sophisticated as the modern
relational- database engines? Why do you think that is?

I don't know - is there? There have certainly been some sophisticated
network servers using async I/O and a single thread of execution. Are
they as sophisticated as a modern relational database? I dunno. Then
again, I already know that async i/o with a single thread of execution
isn't as powerful as threads, so there are almost certainly problem
areas where it isn't suitable and threads are. So what? That doesn't
make the async I/O model any less useful. Of course, if you're only
able to learn one tool, you should probably learn the most powerful
one you can. But just because you only know how to use a hammer
doesn't automatically make everything you encounter a nail.

<mike
 
S

sjdevnull

Mike said:
Let's see. Reality is that writing correct programs is hard. Writing
correct programs that use concurrency is even harder, because of the
exponential explosion of the order that operations can happen
in.

And dont forget:
Writing concurrent programs without protected memory between execution
contexts is even harder than with it.
 
P

phil hunt

Let's see. Reality is that writing correct programs is hard. Writing
correct programs that use concurrency is even harder, because of the
exponential explosion of the order that operations can happen
in. Personally, I'm willing to use anything I can find that makes
those tasks easier.

Indeed so. Use threading (or whatever) when one has to, use an
asynchronous single-threaded process whenever you can.
 
P

Paul Rubin

Indeed so. Use threading (or whatever) when one has to, use an
asynchronous single-threaded process whenever you can.

This is silly. You could say the exact same thing about if
statements. The number of paths through the program is exponential in
the number of if statements executed. So we better get rid of if
statements.

Really, the essence of programming is to find ways of organizing the
program to stay reliable and maintainable in the face of that
combinatorial explosion. That means facing the problem and finding
solutions, not running away. The principle is no different for
threads than it is for if statements.
 
P

phil hunt

This is silly. You could say the exact same thing about if
statements. The number of paths through the program is exponential in
the number of if statements executed. So we better get rid of if
statements.

It's not the number of paths that's important.

What's important is *predictability*, e.g. which instruction will
the computer execute next?

If you only have one thread, you can tell by looking at the code
what gets executed next. It's very simple.

If you have 2 threads you can easily have a timing-based situation
that occurs rarely but which causes your program to behave wierdly.
This sort of bug is very hard to reproduce and therefore to fix.
Really, the essence of programming is to find ways of organizing the
program to stay reliable and maintainable in the face of that
combinatorial explosion.

Yes, and introducing code that makes randomly-occurring bugs more
likely makes debugging inherently harder.
That means facing the problem and finding
solutions, not running away.

Yes, find solutions. Don't find dangerous dead-ends that look like
solutions but which will give you lots of trouble.
 
M

Mike Meyer

Paul Rubin said:
This is silly. You could say the exact same thing about if
statements. The number of paths through the program is exponential in
the number of if statements executed. So we better get rid of if
statements.

The number of paths through a program isn't exponential in the number
of if statements, it's multiplicative. Each if statement multiplies
the number of paths through the program by 2, no matter how many other
statements you have.

On the other hand, with threads, the number of possible execution
orders is the number of threads raised to the power of the number of
instructions (assuming that instructions are atomic, which is probably
false) in the shared code segment. It's a *much* nastier problem.
Really, the essence of programming is to find ways of organizing the
program to stay reliable and maintainable in the face of that
combinatorial explosion. That means facing the problem and finding
solutions, not running away. The principle is no different for
threads than it is for if statements.

Correct. But choosing to use a tool that has a less complex model but
solves the problem is *not* running away. If it were, you'd have to
call using if statements rather than a goto running away, because
that's that's exactly what you're doing.

I do agree that we should face the problems and look for solutions,
because some problems can't be solved with async I/O. That's why I
posted the article titled "Static vs. dynamic checking for support of
concurrent programming" - I'm trying to find out if one potential
solution could be adapted for Python.

<mike
 
P

Piet van Oostrum

PR> This is silly. You could say the exact same thing about if
PR> statements. The number of paths through the program is exponential in
PR> the number of if statements executed. So we better get rid of if
PR> statements.
PR> Really, the essence of programming is to find ways of organizing the
PR> program to stay reliable and maintainable in the face of that
PR> combinatorial explosion. That means facing the problem and finding
PR> solutions, not running away. The principle is no different for
PR> threads than it is for if statements.

The principle is (more or less) similar, but for parallel programs it is an
order of magnitude more complicated. Compare the correctness proofs of
parallel programs with those of sequential programs.
 
B

Bryan Olson

phil said:
> It's not the number of paths that's important.

Absolutely right. Non-trivial software always has too many paths
to consider them individually, so we have to reason generally.
> What's important is *predictability*, e.g. which instruction will
> the computer execute next?
>
> If you only have one thread, you can tell by looking at the code
> what gets executed next. It's very simple.

Not really. Trivially, an 'if' statement that depends upon input
data is statically predictable. Use of async I/O means makes the
programs execution dependent upon external timing.

> If you have 2 threads you can easily have a timing-based situation
> that occurs rarely but which causes your program to behave wierdly.
> This sort of bug is very hard to reproduce and therefore to fix.

So we need to learn to avoid it.


[...]
> Yes, find solutions. Don't find dangerous dead-ends that look like
> solutions but which will give you lots of trouble.

If concurrency is a dead end, why do the programs that provide
the most sophisticated services of any in the world rely on it
so heavily?
 
B

Bryan Olson

Piet said:
>
> The principle is (more or less) similar, but for parallel programs it is an
> order of magnitude more complicated. Compare the correctness proofs of
> parallel programs with those of sequential programs.

That's an artifact of what the research community is trying to
accomplish with the proof. Proving non-trivial programs correct
is currently beyond the state of the art.
 
M

Mike Meyer

Bryan Olson said:
Not really. Trivially, an 'if' statement that depends upon input
data is statically predictable. Use of async I/O means makes the
programs execution dependent upon external timing.

Yes, but that depenency is tied to a single point - the select
call. The paths after that are statically predictable. This makes the
code very managable.
So we need to learn to avoid it.

No, we need tools that make it impossible to write codde that triggers
it. Async I/O is one such tool, but it has lots of other limitations
that make it unsuitable for many applications.
[...]
Yes, find solutions. Don't find dangerous dead-ends that look like
solutions but which will give you lots of trouble.
If concurrency is a dead end, why do the programs that provide
the most sophisticated services of any in the world rely on it
so heavily?

I don't know what Phil is saying, but I'm not calling concurrency a
dead end. I'm calling the tools available in most programming
languages for dealing with it primitive.

We need better tools.

<mike
 
P

phil hunt

If concurrency is a dead end, why do the programs that provide
the most sophisticated services of any in the world rely on it
so heavily?

Some times concurrency is the best (or only) way to do a job. Other
times, it's more trouble than its worth. A good programmer will know
which is which, and will not use an overly complex solution for the
project he is writing.
 
P

phil hunt

I don't know what Phil is saying, but I'm not calling concurrency a
dead end.

In general it isn't. However, in many programs, it might be, in that
by using it you might end up with a very complex program that fails
unpredictably and if hard to debug: if you get in that situation,
you may have to start again, in which case your previous work will
have been a dead end.

(Actually I would suggest that knowing when to throw something away
and start again is something that differentiates between good and
bad programmers).
I'm calling the tools available in most programming
languages for dealing with it primitive.

We need better tools.

I agree.
 
B

Bryan Olson

Mike said:
> Bryan Olson writes:
> phil hunt wrote:
>
>
>
> Yes, but that depenency is tied to a single point - the select
> call. The paths after that are statically predictable. This makes the
> code very managable.

Wow -- I could not disagree more. Returning back to some single
point for every possibly-blocking operation is painful to manage
even for simple GUIs, and humanly intractable for sophisticated
services.

Select is certainly useful, but it scales badly and isn't as
general as better tools.
> [...] I'm calling the tools available in most programming
> languages for dealing with it primitive.
>
> We need better tools.

Agreed, but if 'select' is someone's idea of the state of the
art, they have little clue as to the tools already available.
Bringing the tools to Python remains a bit of challenge, largely
because so many Pythoners are unaware.
 
M

Mike Meyer

Bryan Olson said:
Wow -- I could not disagree more. Returning back to some single
point for every possibly-blocking operation is painful to manage
even for simple GUIs, and humanly intractable for sophisticated
services.

I'd be interested in what you're trying to do that winds up as
unmanagable. There are clearly things select+async IO is unsuitable
for. You may be running into problems because you're trying to use it
in such an environment. For instance, it's not clear to me that it
will work well for any kind of GUI programming, though I've had good
look with it for command line interfaces.
Select is certainly useful, but it scales badly and isn't as
general as better tools.

It can't take advantage of multiple CPUs. I've not run into scaling
problems on single-CPU systems.
[...] I'm calling the tools available in most programming
languages for dealing with it primitive.
We need better tools.
Agreed, but if 'select' is someone's idea of the state of the
art, they have little clue as to the tools already available.

Well, share! If you know of tools that make dealing with concurrent
code more manageable than an async I/O loop and have fewer
restrictions, I'm certainly interested in hearing about them.
Bringing the tools to Python remains a bit of challenge, largely
because so many Pythoners are unaware.

Well, the way to fix that is to talk about them!

<mike
 
B

Bryan Olson

Mike said:
>
> I'd be interested in what you're trying to do that winds up as
> unmanagable.

I'd like to call a utility in someone else's code, but it might
do something that could block. I find re-writing everyone's code
into a state-machine that can trap back to the central I/O loop
and later resume where it left off, to be hard to manage. When
I'm writing my own base classes, I find it hard to support the
back-to-the-I/O-loop-and-resume thing so that method over-rides
can call blocking operations when they need to.

> There are clearly things select+async IO is unsuitable
> for. You may be running into problems because you're trying to use it
> in such an environment. For instance, it's not clear to me that it
> will work well for any kind of GUI programming, though I've had good
> look with it for command line interfaces.

Uh, not sure where you're coming from there. Are you unaware of
the 'event loop' in the GUI's, or unaware that it's async I/O.
>
> It can't take advantage of multiple CPUs. I've not run into scaling
> problems on single-CPU systems.

Select() is linear-time in the number of sockets to be checked
(not just the number found to be ready). There's a good write-up
of the problem and solutions Google-able as "The C10K problem".

>> > [...] I'm calling the tools available in most programming
>> > languages for dealing with it primitive.
>> > We need better tools.
>>Agreed, but if 'select' is someone's idea of the state of the
>>art, they have little clue as to the tools already available.
>
> Well, share!

Uh, where have you been? I keep explaining that concurrency
systems have improved vastly in recent years. For a long time,
the most sophisticated software services generally have used
multiple lines of execution, and now that's mostly in the form
of threads. No one actually disagrees, but they go right on
knocking the modern methods.
 
B

Bengt Richter

[...]
[...] I'm calling the tools available in most programming
languages for dealing with it primitive.
We need better tools.
Agreed, but if 'select' is someone's idea of the state of the
art, they have little clue as to the tools already available.

Well, share!

Uh, where have you been? I keep explaining that concurrency
systems have improved vastly in recent years. For a long time,
the most sophisticated software services generally have used
multiple lines of execution, and now that's mostly in the form
of threads. No one actually disagrees, but they go right on
knocking the modern methods.

I think Mike is asking for references/citations/links to the
"concurrency systems" and "modern methods" you are talking about ;-)
(I'd be interested too ;-)

Regards,
Bengt Richter
 
M

Mike Meyer

Mike said:
Bryan Olson writes:
Trivially, an 'if' statement that depends upon input
data is statically predictable. Use of async I/O means makes the
programs execution dependent upon external timing.
Mike Meyer wrote:
[...]
[...] I'm calling the tools available in most programming
languages for dealing with it primitive.
We need better tools.
Agreed, but if 'select' is someone's idea of the state of the
art, they have little clue as to the tools already available.

Well, share!

Uh, where have you been? I keep explaining that concurrency
systems have improved vastly in recent years. For a long time,
the most sophisticated software services generally have used
multiple lines of execution, and now that's mostly in the form
of threads. No one actually disagrees, but they go right on
knocking the modern methods.

I think Mike is asking for references/citations/links to the
"concurrency systems" and "modern methods" you are talking about ;-)
(I'd be interested too ;-)

Yup. I know systems are getting more concurrent. I also find that the
tools in popular languages for dealing with concurrency suck. I know
of some of these tools myself, but they either have restrictions on
the problems they can solve (like async I/O) or don't integrate well
with Python (like SCOOP).

So I'm definitely interested in learning about other alternatives!

<mike
 
S

sjdevnull

phil said:
Some times concurrency is the best (or only) way to do a job. Other
times, it's more trouble than its worth. A good programmer will know
which is which, and will not use an overly complex solution for the
project he is writing.

Also, a good programmer won't conflate concurrency with threads.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top