Python Runtime sem GIL
em Golang: Grumpy
PYTHONBRASIL 2017
apoio:
+300 milhões de reais/ano
+2 milhões de pedidos/ano
+250 mil profissionais
+3 mil cidades atendidas
- +100 pessoas
-
+60 técnic@s
- Principalmente Ruby
- Python & R
- Javascript
- Java & Swift/Objective-C
PARALELISMO CPYTHON
PARALELISMO GOLANG
GRUMPY TRANSPILER
GRUMPY INTERNALS
PARELELISMO CPYTHON
- Concorrência != Paralelismo
- Global Interpreter Lock (GIL)
- Threading vs Multiprocessing vs AsyncIO
Concorrência != Paralelismo
Paralelismo
Concorrência
Global Interpreter Lock
Green Threads
AsyncIO, Gevent, Twisted, etc...
Não tem
Global Interpreter Lock
- não é interpretado
- [quase] sem Locks (sincronização via Channels)
-
Garbage Colector avançado
- tricolor mark-and-sweep (DIJKSTRA, 1978)
- paralelo
- pausas limitadas -> baixa latência
Por que Python?
P: Que problema Python tenta resolver?
My observation at the time was that computers were getting faster and cheaper at an incredible rate (...). [But] the cost of the programmers to program them remained not going down. (Guido van Rossum, 2008)
Por que Python?
[How] about the indentation in Python?
It's the right thing to do from a code readability (...) [and] from a maintenance point of view. And maintainability of code is what counts most: no program is perfect from the start, and if it is successful, it will be extended. So maintenance is a fact of life, not a necessary evil. (GvR, 2008)
- Facil escrita de código (baixa curva de aprendizagem)
- Fácil leitura e modificação de código (manutenção)
Grumpy Transpiler
Benchmark
def fib(n):
if n < 2:
return 1
return fib(n - 1) + fib(n - 2)
GRUMPY INTERNALS
- Exemplo
- Reuso de código (stdlib)
- Módulos internos
Grumpy Runtime
echo "print 'hello, world'" | make run
echo "print 'hello, world'" | python
package __main__
import πg "grumpy"
var Code *πg.Code
func init() {
Code = πg.NewCode("<module>", "ehlo.py", nil, 0, func(πF *πg.Frame, _ []*πg.Object) (*πg.Object, *πg.BaseException) {
var πR *πg.Object; _ = πR
var πE *πg.BaseException; _ = πE
var πTemp001 []*πg.Object
_ = πTemp001
for ; πF.State() >= 0; πF.PopCheckpoint() {
switch πF.State() {
case 0:
default: panic("unexpected function state")
}
// line 1: print 'hello, world'
πF.SetLineno(1)
πTemp001 = make([]*πg.Object, 1)
πTemp001[0] = πg.NewStr("hello, world").ToObject()
if πE = πg.Print(πF, πTemp001, true); πE != nil {
continue
}
}
return nil, πE
})
πg.RegisterModule("__main__", Code)
}
Grumpy Transpiler
a = 'hello'
b = 'world'
message = ', '.join([a, b])
print message
Grumpy Transpiler
package __main__
import πg "grumpy"
var Code *πg.Code
func init() {
Code = πg.NewCode("<module>", "ehlo.py", nil, 0, func(πF *πg.Frame, _ []*πg.Object) (*πg.Object, *πg.BaseException) {
var πR *πg.Object; _ = πR
var πE *πg.BaseException; _ = πE
ßa := πg.InternStr("a")
ßb := πg.InternStr("b")
ßhello := πg.InternStr("hello")
ßjoin := πg.InternStr("join")
ßmessage := πg.InternStr("message")
ßworld := πg.InternStr("world")
var πTemp001 []*πg.Object
_ = πTemp001
var πTemp002 []*πg.Object
_ = πTemp002
var πTemp003 *πg.Object
_ = πTemp003
var πTemp004 *πg.Object
_ = πTemp004
for ; πF.State() >= 0; πF.PopCheckpoint() {
switch πF.State() {
case 0:
default: panic("unexpected function state")
}
// line 1: a = 'hello'
πF.SetLineno(1)
if πE = πF.Globals().SetItem(πF, ßa.ToObject(), ßhello.ToObject()); πE != nil {
continue
}
// line 2: b = 'world'
πF.SetLineno(2)
if πE = πF.Globals().SetItem(πF, ßb.ToObject(), ßworld.ToObject()); πE != nil {
continue
}
// line 3: message = ', '.join([a, b])
πF.SetLineno(3)
πTemp001 = πF.MakeArgs(1)
πTemp002 = make([]*πg.Object, 2)
if πTemp003, πE = πg.ResolveGlobal(πF, ßa); πE != nil {
continue
}
πTemp002[0] = πTemp003
if πTemp003, πE = πg.ResolveGlobal(πF, ßb); πE != nil {
continue
}
πTemp002[1] = πTemp003
πTemp003 = πg.NewList(πTemp002...).ToObject()
πTemp001[0] = πTemp003
if πTemp003, πE = πg.GetAttr(πF, πg.NewStr(", ").ToObject(), ßjoin, nil); πE != nil {
continue
}
if πTemp004, πE = πTemp003.Call(πF, πTemp001, nil); πE != nil {
continue
}
πF.FreeArgs(πTemp001)
if πE = πF.Globals().SetItem(πF, ßmessage.ToObject(), πTemp004); πE != nil {
continue
}
// line 4: print message
πF.SetLineno(4)
πTemp001 = make([]*πg.Object, 1)
if πTemp003, πE = πg.ResolveGlobal(πF, ßmessage); πE != nil {
continue
}
πTemp001[0] = πTemp003
if πE = πg.Print(πF, πTemp001, true); πE != nil {
continue
}
}
return nil, πE
})
πg.RegisterModule("__main__", Code)
}
a = 'hello'
b = 'world'
message = ', '.join([a, b])
print message
var πR *πg.Object; _ = πR
var πE *πg.BaseException; _ = πE
ßa := πg.InternStr("a")
ßb := πg.InternStr("b")
ßhello := πg.InternStr("hello")
ßjoin := πg.InternStr("join")
ßmessage := πg.InternStr("message")
ßworld := πg.InternStr("world")
a = 'hello'
b = 'world'
message = ', '.join([a, b])
print message
// line 1: a = 'hello'
πF.SetLineno(1)
if πE = πF.Globals().SetItem(πF, ßa.ToObject(), ßhello.ToObject()); πE != nil {
continue
}
// line 2: b = 'world'
πF.SetLineno(2)
if πE = πF.Globals().SetItem(πF, ßb.ToObject(), ßworld.ToObject()); πE != nil {
continue
}
a = 'hello'
b = 'world'
message = ', '.join([a, b])
print message
// line 3: message = ', '.join([a, b])
πF.SetLineno(3)
πTemp001 = πF.MakeArgs(1)
πTemp002 = make([]*πg.Object, 2)
if πTemp003, πE = πg.ResolveGlobal(πF, ßa); πE != nil {
continue
}
πTemp002[0] = πTemp003
if πTemp003, πE = πg.ResolveGlobal(πF, ßb); πE != nil {
continue
}
πTemp002[1] = πTemp003
πTemp003 = πg.NewList(πTemp002...).ToObject()
πTemp001[0] = πTemp003
if πTemp003, πE = πg.GetAttr(πF, πg.NewStr(", ").ToObject(), ßjoin, nil); πE != nil {
continue
}
if πTemp004, πE = πTemp003.Call(πF, πTemp001, nil); πE != nil {
continue
}
πF.FreeArgs(πTemp001)
if πE = πF.Globals().SetItem(πF, ßmessage.ToObject(), πTemp004); πE != nil {
continue
}
a = 'hello'
b = 'world'
message = ', '.join([a, b])
print message
// line 4: print message
πF.SetLineno(4)
πTemp001 = make([]*πg.Object, 1)
if πTemp003, πE = πg.ResolveGlobal(πF, ßmessage); πE != nil {
continue
}
πTemp001[0] = πTemp003
if πE = πg.Print(πF, πTemp001, true); πE != nil {
continue
}
GRUMPY INTERNALS
- Exemplo
- Reuso de código (stdlib)
- Módulos internos
Stdlib
#lib/math.py
from '__go__/math' import (Pi, E, Ceil, ...)
def ceil(x):
return Ceil(float(x))
- CPython
- PyPy
- Ouroboros
- Golang
- third_party/stdlib/StringIO.py
- third_party/pypy/datetime.py
- third_party/ouroboros/operator.py
- lib/math.py
GRUMPY INTERNALS
- Exemplo
- Reuso de código (stdlib)
- Módulos internos
Grumpy Runtime
- object
- int
- threading
// runtime/object.go
package grumpy
// Object represents Python 'object' objects.
type Object struct {
typ *Type `attr:"__class__"`
dict *Dict
ref *WeakRef
}
// runtime/int.go
package grumpy
// Int represents Python 'int' objects.
type Int struct {
Object
value int
}
// runtime/threading.go
package grumpy
type TryableMutex struct {
c chan bool
}
// Lock blocks until the mutex is available and then acquires a lock.
func (m *TryableMutex) Lock() {
<-m.c
}
- biblioteca unittest com funcionamento básico e rodando algumas suítes do CPython (alvo: MAR 2017)
- Todos os benchmarks do CPython rodando (alvo: JUL 2017)
- Todas as suítes de teste do CPython rodando sem erros
(alvo: SET 2017) - Estratégia e design para suportar Python 3 (alvo: OUT 2017)
- Suporte completo a Python 3 (alvo: JUL 2018)
Socorro: Fork Me
Perguntas
alan.justino@yahoo.com.br
@alanjds
?
Obrigado
alan.justino@yahoo.com.br
Perguntas:
Slides:
Python Runtime sem GIL em Golang: Grumpy
By alanjds
Python Runtime sem GIL em Golang: Grumpy
Palesta apresentada na PythonBrasil[13] em Belo Horizonte em outubro de 2017
- 2,523