Uma coisa que eu sempre me confundi sobre ruby e python e a questao do Global Interpreter Locker (GIL). Na verdade, a duvida maior e se operacoes de IO realmente bloqueiam os processos, impedindo a execucao de outras threads.Recentemente li um pouco mais sobre a versao 1.9 do Ruby e como ela passou a utilizar threads do sistema operacional, ao contrario das chamadas Green Threads da versao 1.8. No entanto, o GIL do ruby continua impedindo que duas threads executem ao mesmo tempo. A menos que uma esteja parada executando alguma operacao de IO nao bloqueante.No caso do Python, o pouco de informacao que tenho me leva a crer que a linguagem utiliza Green Threads. Fica entao a minha duvida se mesmo assim e possivel que o processo execute uma outra thread enquanto aguarda um retorno de IO.Para comecar fiz um pequeno script python para simular uma query pesada do MySql sendo executada 4 vezes. Se o script demorar por volta de dois segundo significa que durante uma operacao de IO, o python prosseguiu executando as outras threads:import _mysqlfrom threading import Threaddef executa(): db = _mysql.connect(host="localhost", user="root", passwd="", db="teste") db.query("select sleep(2)") r=db.use_result() r.fetch_row()threads = []for i in range(4): t = Thread(target=executa, args=()) t.start() threads.append(t)for t in threads: t.join() O resultado da execucao pode ser visto abaixo, mostrando que o IO nao bloqueou o programa:> time python teste.pyreal 0m2.030suser 0m0.016ssys 0m0.012sExecutei o mesmo teste com ruby, com o script similar abaixo:require 'mysql2'threads = []4.times do |i| thread = Thread.new do my = Mysql2::Client.new(host: "127.0.0.1", username: "root", database: "teste") my.query("select sleep(2)").collect{|i|i} end thread.run threads << threadendthreads.each do |thread| thread.joinendE o resultado tambem foi satisfatorio:> time ruby teste.rbreal 0m2.178suser 0m0.076ssys 0m0.008sOu seja, tanto python como ruby estao lidando bem com execucao paralela. Mesmo se nao utilizar todos os cores disponiveis, no minimo o IO para o MySql nao esta bloqueando.Com esse bom resultado, resolvi entao subir um pouco mais de nivel e verificar se colocando o Django na equacao poderiamos aproveitar esse bom desempenho. Criei essa pequena view para simular uma query lenta, assim como nos scripts acima, e iniciei o Django (versao 1.3) com o gunicorn.from django.db import connectiondef debug(request): cursor = connection.cursor() cursor.execute("select sleep(2)") return HttpResponse('ok')E o resultado, como pode ser visto abaixo, foi ruim:> ab -n 4 -c 4 http://127.0.0.1:8000/debug/Time taken for tests: 8.161 secondsO mesmo teste executado para a dupla ruby on rails tem resultado parecido:> ab -n 4 -c 4 http://localhost:3000/politicos/Time taken for tests: 8.043 secondsConclusao:Embora python e ruby permitam IO nao bloqueante, os frameworks Django e Rails ainda sao bloqueantes. Um dos motivos daqueles memes de "Rails nao escala" e "Django nao escala". Felizmente sempre ha alternativas.E possivel escalar via processos como explicado em Solucionando IO bloqueante do mysql para Rails, e utilizando varios workers do gunicorn para Django. Caso seja necessario uma escalabilidade maior ainda, o ideal entao e partir para solucoes como Event Machine do ruby, GEvent para Python, ou ate mesmo NodeJs. Combinando essas solucoes com multiplos processos. Nas minhas conversas com os participantes do RecSys de 2015 em Viena foi possivel notar o esgotamento deles