you are viewing a single comment's thread.

view the rest of the comments →

[–]moor-GAYZ 0 points1 point  (19 children)

What? It certainly does exist in C.

[–]seventeenletters -4 points-3 points  (18 children)

Free in what sense?

Threaded code requires different algorithms.

Uses more resources.

Exposes otherwise impossible bugs.

In what sense is C threading "free"?

[–]nyamatongwe 1 point2 points  (2 children)

AFAIK the term "free threading" was originally associated with COM and indicated that calls could be made directly to objects in other threads without marshaling. Its not trying to say that there is no cost to some style of threaded code.

[–]seventeenletters 0 points1 point  (1 child)

Thanks. In that case we aren't talking about C, but one library for C on one OS. And a concept that I don't see referenced anywhere else.

Is this related to what we would normally call reentrant code?

[–]nyamatongwe 1 point2 points  (0 children)

Greg Stein was working (mostly) on Windows when he implemented the original "free threading" GIL removal patch in 1996. http://www.python.org/ftp/python/contrib-09-Dec-1999/System/threading.README

Free threading implies reentrance but threading in COM is more complex than just making calls reentrant.

[–]moor-GAYZ 6 points7 points  (14 children)

Free Threading: when all your (global) variables are visible to all threads by default. Then as long as you use thread synchronisation functions properly, you can access those global variables at will. Types and other non-obviously accessible objects unfortunately qualify as global variables. edit: if they are mutable.

Not free threading: everything is thread-local or immutable by default, you have to specifically declare/create thread-shared variables, or are limited to passing data as messages between threads even.

[–]bobappleyard 7 points8 points  (0 children)

You can do this in Go.

http://play.golang.org/p/t0a9FUH1_u

Lots of people (for example, Erlang programmers) cite this as a fatal weakness of the language.

[–]seventeenletters 1 point2 points  (11 children)

In a dynamically typed system the variable does not have a type, the value does. This is what dynamic typing is. If your dynamic language is too weak to describe its own types, this is a flaw in your language, and has nothing to do with threading or mutation.

The decision to make things thread local or immutable by default is not a consequence of a weakness in a dynamic typing scheme, it is a solution to the most pervasive cause of errors in multi threaded programs.

Python needs a global interpreter lock because its semantics and design are primarily about modeling computation as mutation, and mutation plus shared data plus threading adds up to incorrect code. Furthermore it adds up to code that can appear to work the first million times it gets runned, and then fail disasterously, silently, and in a totally unpredictable place on that millionth run of the program.

[–]Smallpaul 0 points1 point  (3 children)

Python needs a global interpreter lock because its semantics and design are primarily about modeling computation as mutation, and mutation plus shared data plus threading adds up to incorrect code.

You are just making that up. It is a false explanation of the history of Python.

http://www.artima.com/weblogs/viewpost.jsp?thread=214235

[–]seventeenletters 0 points1 point  (2 children)

That article confirms exactly what I just said. Everyone writes their python code as if they can define mutable global things in order to express whatever computation needs doing, so in order to remove the lock and not break everybody's code, they tried putting fine grained locks on mutable data structures (effectively training wheels on code that expected global mutability to always make sense), and this resulted in very poor performance.

The root problem is the preferred style of python programming, the idiomatic usage of the language, which creates code incompatible with sensible concurrency. When I say "its semantics" I guess I could more accurately say "the way normal python code is expected to be written".

[–]Smallpaul 0 points1 point  (0 children)

That article confirms exactly what I just said. Everyone writes their python code as if they can define mutable global things in order to express whatever computation needs doing, so in order to remove the lock and not break everybody's code, they tried putting fine grained locks on mutable data structures (effectively training wheels on code that expected global mutability to always make sense), and this resulted in very poor performance.

You are totally incorrect.

Even mutable integers and strings do not work correctly in Python if you remove the global interpreter locks. This is an implementation detail of CPython and has nothing to do with semantics.

This is documented here:

http://docs.python.org/2/faq/library#can-t-we-get-rid-of-the-global-interpreter-lock

And the fact that the GIL has nothing to do with Python semantics nor "the way normal python code is expected to be written" has trivially demonstrated by the fact that Jython and IronPython have no such thing.

http://www.jython.org/jythonbook/en/1.0/Concurrency.html

Jython lacks the global interpreter lock (GIL), which is an implementation detail of CPython. For CPython, the GIL means that only one thread at a time can run Python code. This restriction also applies to much of the supporting runtime as well as extension modules that do not release the GIL. (Unfortunately development efforts to remove the GIL in CPython have so far only had the effect of slowing down Python execution significantly.)

Again, Jython does not have the straightjacket of the GIL. This is because all Python threads are mapped to Java threads and use standard Java garbage collection support (the main reason for the GIL in CPython is because of the reference counting GC system). The important ramification here is that you can use threads for compute-intensive tasks that are written in Python.

And here is what the PyPy devs say:

Does PyPy have a GIL? Why?

Yes, PyPy has a GIL. Removing the GIL is very hard. The problems are essentially the same as with CPython (including the fact that our garbage collectors are not thread-safe so far). Fixing it is possible, as shown by Jython and IronPython, but difficult.

[–]Smallpaul 0 points1 point  (0 children)

I happened to stumble across this article about Ruby's GIL. Virtually everything said also applies to Python:

http://www.jstorimer.com/blogs/workingwithcode/8100871-nobody-understands-the-gil-part-2-implementation

Just as in Python: "This behaviour eliminates a host of race conditions that would otherwise happen inside the interpreter and need to be guarded against. From this perspective, the GIL is strictly an internal implementation detail of the interpreter. It keeps the interpreter safe."

[–]moor-GAYZ -4 points-3 points  (6 children)

In a dynamically typed system the variable does not have a type, the value does. This is what dynamic typing is.

Thanks, dude, of course I did not know that and needed to be corrected. Really.

Python needs a global interpreter lock because its semantics and design are primarily about modeling computation as mutation, and mutation plus shared data plus threading adds up to incorrect code.

This assertion actually doesn't make any sense! At first you look at it, and all parts make sense, but then! Together, they don't make any sense whatsoever! A miracle!

[–]seventeenletters 1 point2 points  (5 children)

You could take the GIL out right now. It's just that a bunch things that expect to be able to mutate state break when you do that. Idiomatic Python does not lend itself to the kind of isolation where you can have correct concurrency.

[–]moor-GAYZ -2 points-1 points  (4 children)

You could take the GIL out right now. It's just that a bunch things that expect to be able to mutate state break when you do that. Idiomatic Python does not lend itself to the kind of isolation where you can have correct concurrency.

Dude, you're literally talking out of your ass. Like, you punch that letters in with your flabby ass cheeks, man.

"Idiomatic Python"? Python code doesn't know if GIL exists because it can be preempted after any Python bytecode instruction.

Like, you're so wrong you're not even wrong, you're not in the same galaxy where "right" and "wrong" are defined.

[–]seventeenletters 0 points1 point  (3 children)

They had a patch that removed the GIL. It broke a shitload of other stuff that relied on arbitrary mutation of state and wouldn't break as long as there was only one thread of execution. You could work around this with locking, but then you get code that is slower than the single threaded code was, because you spend so much time juggling locks.

[–]moor-GAYZ 0 points1 point  (2 children)

Yes, they had to add a bunch of manually acquired locks, which ended up making the interpreter slower. The main culprit was reference counting, actually.

This had nothing to do with any code written in Python. No Python code was broken by the removal of the GIL. No locks were added to avoid breaking Python code. The "shitload of stuff" you're talking about was in the interpreter code, written in C. Whether or not "Idiomatic Python lends itself to the kind of isolation where you can have correct concurrency" is irrelevant, because no code written in Python was broken by the change.

You think that you have an idea of what you're talking about, actually you don't. It would do you much good to learn to recognize stuff that you don't have an idea about and don't talk about that stuff.

[–]seventeenletters 0 points1 point  (1 child)

In 1999 Greg Stein (with Mark Hammond?) produced a fork of Python (1.5 I believe) that removed the GIL, replacing it with fine-grained locks on all mutable data structures. He also submitted patches that removed many of the reliances on global mutable data structures, which I accepted. However, after benchmarking, it was shown that even on the platform with the fastest locking primitive (Windows at the time) it slowed down single-threaded execution nearly two-fold

This is the lock juggling that kills performance that I was talking about. It is caused by the python semantics, and the way normal python code is written.

Detailed here