Python Global Interpreter Lock (GIL)

Python = CPython

First, what is a GIL? A GIL is a mechanism to only execute code from one thread at a time. It is an exclusive lock in the interpreter which can only be hold by one thread and must be released to get code of an other thread executed. So for every language using a GIL, there is no real multithreading in sense of using multiple CPUs or cores at the same time.

Python is using a GIL and a lot of people are saying Python sucks, because of it. Well, I don’t, because a GIL can be great. In fact, for all programmers out there, which are not so experienced with multithreading and all the pain of resource locking, which comes with it, you don’t need to care about it, because the GIL does it. The GIL prevents threads from accessing the same resources at the same time. The even better news are, the GIL will be released, if the executing thread is calling a C function, which blocks. If you’re doing blocking I/O or a blocking system call, other threads can be executed in the mean time.

But there is a downside with the Python GIL. Not because of the idea behind a GIL, but because of the implementation of the GIL in Python. I recently found a talk from David Beazley, which brought a lot of light in all the dark things happening around the Python GIL. So, I don’t go into details with the Python GIL, just check out his talk. If you like to do real multitasking have a look at multiprocessing.

If you already know, the kind of old video, just relax and waste your time somewhere else.

Plans to build my own gaming console

I love playing old video games for the SNES or N64 gaming consoles, but I don’t own the consoles. So I sometimes do very illegal things like playing old Nintendo games on PC with an emulator. It’s very easy to setup and getting the game ROMs is no problem at all. But having a full-blown computer running all the time for playing such games is a real waste and you never get the original gaming experience, because of playing with computer compatible gaming controllers.

So I thought, why not build a very small and very cheap piece of hardware, which can run all of my favorite old games and support the original game controllers. The gaming experience should be as near as possible to the old Nintendo gaming consoles, but with certain features like internet connection or USB support.

Here is a list of features, which my homebrew console should have:

  • Run emulators for SNES and N64 games, maybe SEGA systems, too
  • Graphics output via HDMI
  • Audio output
  • USB support
  • Network support (Internet for downloading games, or storing save games)
  • Support original game controllers for SNES and N64, maybe PlayStation, without modifying the controller
  • Very small, should fit in my pocket
  • Cheap cheap cheap

The most important part is the main board. After some research I found two boards, which fit my requirements.

  • Raspberry Pi model B – Costs: 25.- Euro
    Raspberry PI model B
  • BeagleBoard – Costs: 107.- Euro
    BeagleBoard

I would prefer the Raspberry PI, not only because of the prize, but because of the size.
For connecting my favorite gaming controller to this device we need to adapt the controller to USB. There are several manuals out there for building connectors, which adapt the original controller socket to USB. My first supported controllers should be SNES and N64.

Raphnet Tech got all kind of connectors. If you don’t like to build them yourself, you can buy them, too. I prefer building them myself.

The controller connectors should not be part of the console casing itself, but plugable via USB.
The OS running on my homebrew gaming console should be Linux with a small X frontend for starting and downloading games. All parts of software should be controlled via the gaming controller, no keyboards or mice allowed! The casing should be solid metal, nothing fancy, but very stable.

That’s it for now. If you have ideas or hints for hardware, which could be used, feel free to comment. The Raspberry PI is very popular right now and I’m on a waiting list to get one, so I need to wait with my little project to start, until it’s shipped. If you own one and don’t need it, I’ll take it. ;)

Create a local PyPI mirror

I assume you’re using Linux
Tested with Ubuntu 10.04.4 LTS

Some servers I administrate don’t have an internet connection, because of security reasons or they just don’t need to have one. The lack of an internet connection is pretty bad, when it comes to installing packages from PyPI. To enable my offline servers to get packages from PyPI I need a local mirror. First I thought I use wget and it’s mirroring feature, but I found out, there already is a PEP 381 for mirroring PyPI infrastructure and there already is a client for applying PEP 381.

Because I’ve a dedicated server for hosting mirrors, I choose this server to host my local PyPI mirror, too. It’s pretty easy, just install a virtualenv (optional but cleaner) and install pep381client.

virtualenv --no-site-packages pypi_mirror
source pypi_mirror/bin/activate
pip install pep381client
mkdir pypi_mirror/data/
pep381run pypi_mirror/data/

Now pep381run will start mirroring PyPI. After you completed the first run you can execute pep381run regularly via cron, to sync your local mirror with PyPI. A full mirrored PyPI will consume about 30GB of storage.

For a daily sync create /etc/cron.d/pypi_mirror:

45 5 * * * /path/pep381client/pep381run -q /path/pypi/data

If you like to get an email of all changes done in a sync you could use:

MAILTO=you@address.tld
45 5 * * * /path/pep381client/pep381run /path/pypi/data

For hosting your local PyPI mirror, you could use Nginx or Apache. I choose Nginx and my config looks like this:

server {
    listen 10.1.2.3:80;
    server_name pypi.domain.local;
    access_log /var/log/nginx/pypi.domain.local.access.log;
    location / {
        root /var/local/pypi_mirror/data/web;
        autoindex on;

        allow 10.1.2.0/24;
        allow 127.0.0.1;
        deny all;
    }
}

To use your new mirror you can install packages by telling pip from where to download the packages with the --index-url option.

pip install --index-url=http://pypi.domain.local/simple somepackage

If you like to install always from your own mirror you can create a pip config in your home directory.

~/.pip/pip.conf

[global]
index-url = http://pypi.domain.local/simple

The mirror can only be used for installing packages not for searching, because the search feature in pip is API based, which this method does not support. If you need more features than just a raw mirror for installing packages have a look at chishop or crate.io.

Help fighting spam! blackhole.mx

blackhole.mx

We at abusix launched a service a while ago, named blackhole.mx. blackhole.mx involves everyone, who owns a domain or is using Thunderbird, in fighting spam. Basically we try to fight network abuse by reporting it to the provider in charge, or supporting the provider with handling all this abuse reports. If you own a domain, but don’t use SMTP service with it, you can point the MX record to our systems and we will handle incoming spam and cleaning up your domain. If you use the SMTP service, or don’t own any domains, you can install the Thunderbird add-on for reporting spam directly from your mail client to us. We don’t care about your personal data, so we only send the mail headers and your mail address will be anonymized. If you like contributing in fighting spam check blackhole.mx.

Whats up with True and False in Python 2

The following is true for the CPython implementation!

Maybe you noticed or already read about it. There is a difference in using
True/False and integer 1/0 for expressing the bool true and false. The expression itself results in the same True and 1 means bool true and False and 0 means bool false. But performance wise True and 1 are different.

Timing True
from timeit import Timer
t = Timer('True')
print t.repeat(3, number=100000000)

Result: [3.35, 3.34, 3.35]

Timing 1
from timeit import Timer
t = Timer('1')
print t.repeat(3, number=100000000)

Result: [1.27, 1.27, 1.28]

As you can see 1 is in average 2.07 seconds faster than True. Ok executing the statement 100000000 times is pretty much, but imagine a high performance while infinity loop, 2 seconds can matter! The question is, why is there a difference.

PyIntObject _Py_ZeroStruct = {
PyObject_HEAD_INIT(&PyBool_Type)
0
};

PyIntObject _Py_TrueStruct = {
PyObject_HEAD_INIT(&PyBool_Type)
1
};

#define Py_False ((PyObject *) &_Py_ZeroStruct)
#define Py_True ((PyObject *) &_Py_TrueStruct)

This is the C code which defines the Python True and False statements. As you can see True and False are int objects with limited features. True is mapped to int value 1 and False to 0.

>>> type(True)
<type 'bool'>
>>> True + True
2

All of this is nice to know, but not the performance issue. The issue is that True and False in Python are globals and not constants. Let me show you the disassembled bytecode of a = True.

0 LOAD_GLOBAL 0 (True)
3 STORE_FAST 0 (a)

And now have a look at a = 1.

0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (a)

In case of the True, Python need to look up the global name True and this takes some time. In fact you can do really bad things in Python 2.x, because of this.

>>> True = 0
>>> False = 1
>>> True
0
>>> False
1

But the good news is, they changed it in Python 3 and a = True now looks like this.

0 LOAD_CONST 1 (True)
3 STORE_FAST 0 (a)

I hope I didn’t miss anything important about this topic. If so, let me know and enlighten me!

UPDATE
A comment suggested I should have a look into the pypy implementation and I did. True and False are globals in pypy, too. But the globals lookup, object creation and everything else is way way faster in pypy. I’m really impressed.

Here are the timing results:

True/False: [0.16, 0.14, 0.14]
1/0: [0.16, 0.14, 0.16]

Thats a big difference and I’m not completely sure, if the test I used for CPython can be applied the same on pypy. I never looked into pypy before, maybe someone can clear things up.

Pitfall Python Objects

The following is true for the CPython implementation!

All data in Python are objects.

>>> type(1)
<type 'int'>
>>> type('foo')
<type 'str'>
>>> type([])
<type 'list'>

But there are two different kind of objects. Objects whose value can change are called mutable and objects whose value can’t change are called immutable. For example an integer like 1 or a string like 'foo' are both immutable objects. So if you type a = 'foo', a is pointing to an immutable object. You can change the pointer of a by assigning a new object to a, but you can’t change the value of the object 'foo'. Confused? Quick example:

>>> a = 'foo'
>>> id(a)
3074084016L
>>> a[0]
'f'
>>> a[0] = 'z'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> a = 'zoo'
>>> id(a)
3074084088L

For this to make sense you must know how data is stored in memory. One approach could be:

a = String() # Make a new string and assign the string to variable
a.value = 'foo' # Set the string to value 'foo'

For storing a new string the system now try to allocate space in memory. If there is free memory we get an address space and can assign the value of the string. Every string you create will have it’s own address space in memory. The more strings you create, the more memory you will consume, regardless of the value of the string. Not so in Python.

>>> a = 'foo'
>>> b = 'foo'
>>> c = 'foo'
>>> d = 'foo'

Only the first created string object will consume memory. The memory
manager of Python checks if there already is a reference to the string object
'foo'. If yes the variable will point to the address space of the already existing string object.

Check it:

>>> a = 'foo'
>>> b = 'foo'
>>> c = 'foo'
>>> d = 'foo'
>>> id(a)
3074084112L
>>> id(b)
3074084112L
>>> id(c)
3074084112L
>>> id(d)
3074084112L

As you can see a, b, c and d are pointing to the same address space. So, a, b,
c and d are equal. Not only string equal, also object equal. But this is only true for immutable objects like strings, numbers, tuples etc. Mutable objects are working like the first approach. You create a new object and they will have their own address space and consume memory. A list is an example for a mutable object.

>>> a = []
>>> b = []
>>> c = []
>>> d = []
>>> id(a)
3074110316L
>>> id(b)
3074111916L
>>> id(c)
3074111884L
>>> id(d)
3074112012L

a, b, c and d are pointing to different address spaces. A lot of words, but where
is the pitfall?

The issue is, regardless of the behaivor of mutable objects and the knowledge that every new object will have it’s own address space, you can get in serious trouble.

What do you think will happen here?

>>> a = []
>>> b = a

  1. Because the list object is mutable, the value of a will be copied to b. So we have two lists with the same values, but different address spaces.
  2. a is assigned to a new list object and b is pointing to the object of a, so the object of a and b will be equal.

Maybe this helps.

>>> a = []
>>> b = a
>>> id(a)
3074112332L
>>> id(b)
3074112332L

So if your answer is 1, you failed! And you would be in great trouble if you would have done something like this.

>>> a = [5,4,3,2,1]
>>> tmp = a
>>> for index, value in enumerate(a):
... a[index] = value * 2
...
>>> a
[10, 8, 6, 4, 2]
>>> tmp
[10, 8, 6, 4, 2]

Oh sh*t your tmp variable just changed, too?! If you like to preserve the values of a list and modify the original one, don’t do it like this. Force a new object instead!

>>> a = [5,4,3,2,1]
>>> tmp = list(a)
>>> for index, value in enumerate(a):
... a[index] = value * 2
...
>>> a
[10, 8, 6, 4, 2]
>>> tmp
[5, 4, 3, 2, 1]
>>> id(a)
3074110700L
>>> id(tmp)
3074112460L

UPDATE:
For nested lists the example above does not apply. For nested lists use the copy module.

Thanks to teferi!

>>> a = [[1], 2]
>>> tmp = list(a)
>>> a[0].append(3)
>>> tmp
[[1, 3], 2]

To do this kind of copying correctly – you should use copy module. copy.deepcopy does things right.

>>> a = [[1], 2]
>>> tmp = copy.deepcopy(a)
>>> a[0].append(3)
>>> tmp
[[1], 2]
>>> a
[[1, 3], 2]