Interpreter Locker impede que duas threads executem ao mesmo tempo. Uma thread so e executada quando nenhuma outra estiver executando. A solucao mais comum para aproveitar todos os cores de uma maquina em python e abandonar threads e utilizar varios processos. No entanto ha uma maneira de aproveitar todos os cores com threads no python. Para isso vamos precisar criar uma extensao em C.Primeiro vamos criar uma extensao que nao libere o GIL para podermos comparar e conferir a melhoria de performance depois. O pivo dessa extensao e a seguinte funcao:static int reduce_com_gil(int max, int (*f)(int x, int y)) { int retorno = 0; int i; for(i=0; i < max; i++){ retorno = (*f)(retorno, i); } return retorno;}Essa funcao faz algo similar ao que um reduce faria, mas indo de 0 ao valor indicado em max. Para cada iteracao a funcao enviada como segundo parametro e executada. A ideia e causar um grande processamento para que meu core fique travado. O uso dela esta descrito no codigo abaixo:static PyObject *antigil_calcular_com_gil(PyObject *self) { int valor = reduce_com_gil(100*1000, *antigil_calculos); char numero [5000]; sprintf(numero, "%d", valor ); return Py_BuildValue("s", numero);}Repare que eu passo para a funcao reduce_com_gil o ponteiro da funcao antigil_calculos. Essa outra funcao faz diversos calculos a cada iteracao do reduce. O nome antigil e o nome da extensao de exemplo. O codigo completo da extensao pode ser visto aqui.Instalada a extensao, podemos testar a performance da lib com o seguinte codigo:import antigilantigil.calcular_com_gil()E o seguinte comando:$ time python teste.pyreal 0m2.702suser 0m2.692sMas o que a gente quer e saber como se comportam as threads. No caso o seguinte script abre 4 threads para aproveitar os 4 cores da minha maquina:import antigilfrom threading import Threadthreads = []for i in xrange(4): t = Thread(target=antigil.calcular_com_gil) t.start() threads.append(t)for t in threads: t.join()No entando, acaba nao aproveitando. Repare que ao executar 4 threads, o GIL age e impede que duas sejam executadas ao mesmo tempo. Dessa forma so um core da maquina e aproveitado. Isso pode ser observado pelo tempo total que e aproximadamente quatro vezes o tempo de execucao de uma:$ time python teste.pyreal 0m10.910suser 0m10.881sBom, vamos entao a extensao nao bloqueante. A chave do sucesso nesse caso sao as macros Py_BEGIN_ALLOW_THREADS e Py_END_ALLOW_THREADS que respectivamente liberam o GIL e obtem o GIL de volta. Essas macros estao definidas em Python.h. O codigo da funcao reduce ficaria assim:static int reduce_sem_gil(int max, int (*f)(int x, int y)) { int retorno = 0; Py_BEGIN_ALLOW_THREADS int i; for(i=0; i < max; i++){ retorno = (*f)(retorno, i); } Py_END_ALLOW_THREADS return retorno;}Pronto, basta criar a funcao antigil_calcular_sem_gil similar a antigil_calcular_com_gil, utilizando a funcao reduce_sem_gil e entao podemos repetir o teste. No caso parametrizei o script de teste para que voce possa escolher qual funcao deseja executar:import antigilfrom threading import Threadimport sysif 'com-gil' in sys.argv: calcular = antigil.calcular_com_gilelif 'sem-gil' in sys.argv: calcular = antigil.calcular_sem_gilelse: print "Informar com-gil ou sem-gil" exit(0)threads = []for i in xrange(4): t = Thread(target=calcular) t.start() threads.append(t)for t in threads: t.join()O resultado e bem animador e mostra bem que o codigo rodou em paralelo:$ time python teste.py sem-gilreal 0m3.414suser 0m13.413sComo o