View
71
Download
3
Category
Preview:
Citation preview
Java para Lderes e Gerentes
Trilha Ruby
Guilherme Baptista
10 anos deixando linhas de
cdigo por a em lugares como:
Stack Level too Deep
Tail Call Optimization
uma boa ideia fazer recurso em Ruby?
Familiar?
file.rb:10:in `call':stack level too deep (SystemStackError)from file.rb:10:in `'
Qual o significado?
file.rb:10:in `call':stack level too deep (SystemStackError)from file.rb:10:in `'
Qual o significado?
file.rb:10:in `call':stack level too deep (SystemStackError)from file.rb:10:in `'
stack overflow?
file.rb:10:in `call':stack level too deep (SystemStackError)from file.rb:10:in `'
stack overflow?
?
file.rb:10:in `call':stack level too deep (SystemStackError)from file.rb:10:in `'
O que ?
uma proteo contra loops infinitos?
uma proteo contra loops infinitos?
uma proteo contra loops infinitos?
uma proteo contra loops infinitos?
uma proteo contra loops infinitos?
um erro causado por uso de memria em excesso?
um erro causado por uso de memria em excesso?
um erro causado por uso de memria em excesso?
um erro causado por uso de memria em excesso?
file.rb:8:in `':failed to allocate memory (NoMemoryError)
Bnus: Uma linha para acabar com a memria RAM em segundos:
Obs.: No rodar no irb do seu servidor em produo... #fikdik
uma proteo para no deixar um mtodo chamar a si mesmo?
uma proteo para no deixar um mtodo chamar a si mesmo?
uma proteo para no deixar um mtodo chamar a si mesmo?
Done!
uma proteo para no deixar um mtodo chamar a si mesmo muitas vezes?
uma proteo para no deixar um mtodo chamar a si mesmo muitas vezes?
uma proteo para no deixar um mtodo chamar a si mesmo muitas vezes?
Done!
uma proteo para no deixar um mtodo chamar a si mesmo infinitamente?
uma proteo para no deixar um mtodo chamar a si mesmo infinitamente?
file.rb:2:in `me_myself_and_i': stack level too deep (SystemStackError) from file.rb:2:in `me_myself_and_i' from file.rb:2:in `me_myself_and_i' from file.rb:2:in `me_myself_and_i' from file.rb:2:in `me_myself_and_i' ... 11901 levels... from file.rb:2:in `me_myself_and_i' from file.rb:2:in `me_myself_and_i' from file.rb:2:in `me_myself_and_i' from file.rb:5:in `'
Ser?
5
1 + 1 + 1 + 1 + 1
5
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
20000
20000
file.rb:7:in `eval': stack level too deep (SystemStackError) from file.rb:7:in `'
uma proteo para no deixar um mtodo chamar a si mesmo infinitamente?
file.rb:7:in `eval': stack level too deep (SystemStackError) from file.rb:7:in `'
Pode no ser bem isso...
Vamos falar sobre pilha:
Stack(abstract data type)
LIFO: last-in, first-out
(o ltimo que entra o primeiro que sai)
Stack (LIFO: last-in, first-out)
Stack
Stack (LIFO: last-in, first-out)
Stack (LIFO: last-in, first-out)
Stack (LIFO: last-in, first-out)
Stack (LIFO: last-in, first-out)
Stack (LIFO: last-in, first-out)
Stack (LIFO: last-in, first-out)
Stack (LIFO: last-in, first-out)
Em Ruby tudo objeto.
RubyVM::InstructionSequence
RubyVM::InstructionSequence.of
Proc
Ou
method
Ruby Code
down to
VM Instructions
YARB\x02\x00\x00\x00\x03\x00\x00\x00r\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\xF9\x01\x00\x00\xFD\x01\x00\x00b\x02\x00\x00x86_64-linux\x00*\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00*\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00Z\x00\x00\x00\x00\x00\x00\x00Z\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Z\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Z\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\v\x00\x00\x00\x02\x00\x00\x00\r\x00\x00\x00\x11\x00\x00\x00\x0F\x00\x00\x00\x13\x00\x00\x00\r\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x14\x00\x00\x009\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\xD9\x00\x00\x00\x00\x00\x00\x00\xF9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00)\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\xF1\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00(irb)E\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\a\x00\x00\x00\x00\x00\x00\x00the_sumE\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00+\r\x02\x00\x00\x19\x02\x00\x002\x02\x00\x00M\x02\x00\x00
== disasm: #========================================0000 trace 8 ( 54)
0002 trace 1 ( 55)
0004 putobject_OP_INT2FIX_O_1_C_
0005 putobject_OP_INT2FIX_O_1_C_
0006 opt_plus ,
0009 putobject_OP_INT2FIX_O_1_C_
0010 opt_plus ,
0013 putobject_OP_INT2FIX_O_1_C_
0014 opt_plus ,
0017 trace 16 ( 56)
0019 leave ( 55)
putobject_OP_INT2FIX_O_1_C_
putobject_OP_INT2FIX_O_1_C_
opt_plus p3
putobject_OP_INT2FIX_O_1_C_
putobject_OP_INT2FIX_O_1_C_
opt_plus n3 > p2 > n4 > p3
putobject_OP_INT2FIX_O_1_C_
putobject_OP_INT2FIX_O_1_C_
opt_plus n3 > p2 > n4 > p3
putobject_OP_INT2FIX_O_1_C_
putobject_OP_INT2FIX_O_1_C_
opt_plus n3 > p2 > n4 > p3
Recurso?
Recurso:
Capacidade que uma rotina (funo ou mtodo) possui de invocar a si mesma.
Recurso:
Condio de parada:
Hi Fulano!
Hi Fulano!
Hi Fulano!
Recurso vs Iterao
Como contar a quantidade de itens em uma lista?
Array:
Iterao:
Iterao:
Array:
4
Array:
4
Iterao:
Iterao:
Array:
4
Iterao:
Array:
4
Transformar todas as letras em maisculas:
["A", "B", "C", "D"]
Mas no dia a dia no fazemos exatamente assim...
Como realmente fazemos:
E com recurso?
Head / Tail
A
Head
Tail
B
Head
A
Head
Tail
A
Head
Tail
A
Head
Tail
Como contar a quantidade de itens em uma lista?
count(["A", "B", "C", "D"])
count(["B", "C", "D"])
count(["C", "D"])
count(["D"])
count([])
1 + count(["B", "C", "D"])
1 + 1 + count(["D", "D"])
1 + 1 + 1 + count(["D"])
1 + 1 + 1 + 1 + count([])
1 + 1 + 1 + 1 + 0
4
Como somar todos os itens de uma lista?
1 + sum([2, 2, 2])
1 + 2 + sum([2, 2])
1 + 2 + 2 + sum([2])
1 + 2 + 2 + 2 + sum([])
1 + 2 + 2 + 2 + 0
7
E por a vai...
Stack Overflow
Stack Overflow1 + count(["B", "C", "D"])
1 + count(["C", "D"])
1 + count(["D"])
1 + count([])
0
Tamanho do seu Stack
Stack Overflow1 + count(["B", "C", "D"])
1 + count(["C", "D"])
1 + count(["D"])
1 + count([])
0
Stack Overflow
Stack Overflow1 + count(["B", "C", "D"])
1 + count(["C", "D"])
1 + count(["D"])
1 + count([])
0
stack level too deep
(SystemStackError)
Stack Overflowfile.rb:7:in `eval': stack level too deep (SystemStackError) from file.rb:7:in `'
Stack Overflowstack level too deep
(SystemStackError)
s1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
E a?
Opo 1:Aumentar o tamanho do Stack
ulimit -allcore file size (blocks, -c) 0data seg size (kbytes, -d) unlimitedscheduling priority (-e) 0file size (blocks, -f) unlimitedpending signals (-i) 31321max locked memory (kbytes, -l) 64max memory size (kbytes, -m) unlimitedopen files (-n) 1024pipe size (512 bytes, -p) 8POSIX message queues (bytes, -q) 819200real-time priority (-r) 0stack size (kbytes, -s) 8192cpu time (seconds, -t) unlimitedmax user processes (-u) 31321virtual memory (kbytes, -v) unlimitedfile locks (-x) unlimited
RubyVM::DEFAULT_PARAMS{
thread_vm_stack_size: 1048576,
thread_machine_stack_size: 1048576,
fiber_vm_stack_size: 131072,
fiber_machine_stack_size: 524288
}
Opo 2:Tail Call Optimization
cTail Call Optimization1 + count(["B", "C", "D"])
1 + count(["C", "D"])
1 + count(["D"])
1 + count([])
0
stack level too deep
(SystemStackError)
c
Tail Call Optimization
count(["A", "B", "C", "D"], 0)
count(["B", "C", "D"], 1)
count(["C", "D"], 2)
count(["D"], 3)
count([], 4)
4
Tamanho do seu Stack
Reaproveitamento do seu Stack
file.rb:11:in `count': stack level too deep (SystemStackError)
from file.rb:11:in `count'
from file.rb:11:in `count'
from file.rb:11:in `count'
from file.rb:11:in `count'
from file.rb:11:in `count'
from file.rb:11:in `count'
from file.rb:11:in `count'
from file.rb:11:in `count'
... 8723 levels...
from file.rb:11:in `count'
from file.rb:11:in `count'
from file.rb:11:in `count'
from file.rb:17:in `'
Precisamos compilar o nosso cdigo com instrues especficas para a RubyVM / YARV
== disasm: #=====================================local table (size: 5, argc: 1 [opts: 1, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 5] list [ 4] acc [ 3] head [ 2] tail
0000 putobject_OP_INT2FIX_O_0_C_ ( 4)
0001 setlocal_OP__WC__0 4
0003 trace 8
0005 trace 1 ( 6)
0007 getlocal_OP__WC__0 5
0009 opt_empty_p ,
0012 branchunless 21
0014 nop
0015 nop
0016 getlocal_OP__WC__0 4
0018 trace 16
0020 leave
0021 trace 1 ( 8)
0023 getlocal_OP__WC__0 5
0025 opt_send_without_block ,
0028 setlocal_OP__WC__0 3
0030 trace 1 ( 9)
0032 getlocal_OP__WC__0 5
0034 setlocal_OP__WC__0 2
0036 trace 1 ( 11)
0038 putself
0039 getlocal_OP__WC__0 2
0041 getlocal_OP__WC__0 4
0043 putobject_OP_INT2FIX_O_1_C_
0044 opt_plus ,
0047 opt_send_without_block ,
0050 trace 16 ( 13)
0052 leave ( 11)
== disasm: #=====================================local table (size: 5, argc: 1 [opts: 1, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 5] list [ 4] accc [ 3] head [ 2] tail
0000 putobject_OP_INT2FIX_O_0_C_ ( 4)
0001 setlocal_OP__WC__0 4
0003 trace 8
0005 trace 1 ( 6)
0007 getlocal_OP__WC__0 5
0009 opt_empty_p ,
0012 branchunless 21
0014 nop
0015 nop
0016 getlocal_OP__WC__0 4
0018 trace 16
0020 leave
0021 trace 1 ( 8)
0023 getlocal_OP__WC__0 5
0025 opt_send_without_block ,
0028 setlocal_OP__WC__0 3
0030 trace 1 ( 9)
0032 getlocal_OP__WC__0 5
0034 setlocal_OP__WC__0 2
0036 trace 1 ( 11)
0038 putself
0039 getlocal_OP__WC__0 2
0041 getlocal_OP__WC__0 4
0043 putobject_OP_INT2FIX_O_1_C_
0044 opt_plus ,
0047 opt_send_without_block ,
0050 trace 16 ( 13)
0052 leave ( 11)
Acompanhar eventos durante a execuo do cdigo internamente na VMstackprof ruby-prof
trace + tail call optimization
=
== disasm: #=====================================local table (size: 5, argc: 1 [opts: 1, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 5] list [ 4] acc [ 3] head [ 2] tail
0000 putobject_OP_INT2FIX_O_0_C_ ( 2)
0001 setlocal_OP__WC__0 4
0003 getlocal_OP__WC__0 5 ( 3)
0005 opt_empty_p ,
0008 branchunless 15
0010 nop
0011 nop
0012 getlocal_OP__WC__0 4
0014 leave
0015 getlocal_OP__WC__0 5 ( 5)
0017 opt_send_without_block ,
0020 setlocal_OP__WC__0 3
0022 getlocal_OP__WC__0 5 ( 6)
0024 setlocal_OP__WC__0 2
0026 putself ( 8)
0027 getlocal_OP__WC__0 2
0029 getlocal_OP__WC__0 4
0031 putobject_OP_INT2FIX_O_1_C_
0032 opt_plus ,
0035 opt_send_without_block ,
0038 leave
== disasm: #=====================================local table (size: 5, argc: 1 [opts: 1, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 5] list [ 4] acc [ 3] head [ 2] tail
0000 putobject_OP_INT2FIX_O_0_C_ ( 2)
0001 setlocal_OP__WC__0 4
0003 getlocal_OP__WC__0 5 ( 3)
0005 opt_empty_p ,
0008 branchunless 15
0010 nop
0011 nop
0012 getlocal_OP__WC__0 4
0014 leave
0015 getlocal_OP__WC__0 5 ( 5)
0017 opt_send_without_block ,
0020 setlocal_OP__WC__0 3
0022 getlocal_OP__WC__0 5 ( 6)
0024 setlocal_OP__WC__0 2
0026 putself ( 8)
0027 getlocal_OP__WC__0 2
0029 getlocal_OP__WC__0 4
0031 putobject_OP_INT2FIX_O_1_C_
0032 opt_plus ,
0035 opt_send_without_block ,
0038 leave
== disasm: #=====================================local table (size: 5, argc: 1 [opts: 1, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 5] list [ 4] acc [ 3] head [ 2] tail
0000 putobject_OP_INT2FIX_O_0_C_ ( 2)
0001 setlocal_OP__WC__0 4
0003 getlocal_OP__WC__0 5 ( 3)
0005 opt_empty_p ,
0008 branchunless 15
0010 nop
0011 nop
0012 getlocal_OP__WC__0 4
0014 leave
0015 getlocal_OP__WC__0 5 ( 5)
0017 opt_send_without_block ,
0020 setlocal_OP__WC__0 3
0022 getlocal_OP__WC__0 5 ( 6)
0024 setlocal_OP__WC__0 2
0026 putself ( 8)
0027 getlocal_OP__WC__0 2
0029 getlocal_OP__WC__0 4
0031 putobject_OP_INT2FIX_O_1_C_
0032 opt_plus ,
0035 opt_send_without_block ,
0038 leave
== disasm: #=====================================local table (size: 5, argc: 1 [opts: 1, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 5] list [ 4] acc [ 3] head [ 2] tail
0000 putobject_OP_INT2FIX_O_0_C_ ( 2)
0001 setlocal_OP__WC__0 4
0003 getlocal_OP__WC__0 5 ( 3)
0005 opt_empty_p ,
0008 branchunless 15
0010 nop
0011 nop
0012 getlocal_OP__WC__0 4
0014 leave
0015 getlocal_OP__WC__0 5 ( 5)
0017 opt_send_without_block ,
0020 setlocal_OP__WC__0 3
0022 getlocal_OP__WC__0 5 ( 6)
0024 setlocal_OP__WC__0 2
0026 putself ( 8)
0027 getlocal_OP__WC__0 2
0029 getlocal_OP__WC__0 4
0031 putobject_OP_INT2FIX_O_1_C_
0032 opt_plus ,
0035 opt_send_without_block ,
0038 leave
== disasm: #=====================================local table (size: 5, argc: 1 [opts: 1, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 5] list [ 4] acc [ 3] head [ 2] tail
0000 putobject_OP_INT2FIX_O_0_C_ ( 2)
0001 setlocal_OP__WC__0 4
0003 getlocal_OP__WC__0 5 ( 3)
0005 opt_empty_p ,
0008 branchunless 15
0010 nop
0011 nop
0012 getlocal_OP__WC__0 4
0014 leave
0015 getlocal_OP__WC__0 5 ( 5)
0017 opt_send_without_block ,
0020 setlocal_OP__WC__0 3
0022 getlocal_OP__WC__0 5 ( 6)
0024 setlocal_OP__WC__0 2
0026 putself ( 8)
0027 getlocal_OP__WC__0 2
0029 getlocal_OP__WC__0 4
0031 putobject_OP_INT2FIX_O_1_C_
0032 opt_plus ,
0035 opt_send_without_block ,
0038 leave
1000000
Por qu?
Mais rpido que iterar?
user system total real .each: 16.480000 0.000000 16.480000 ( 16.492415)recursion: 26.280000 0.380000 26.660000 ( 26.652826)
Maior proximidade com conceitos delinguagens funcionais
Considerada uma forma elegante de resolver problemas
Quicksort em C utilizando iterao
Quicksort em Haskell utilizando recurso
Maneira de lidar com diferentesestruturas de dados
Listas Ligadas
Grafos
rvores Binrias
Mais uma maneira de resolver problemas e entender os detalhes da linguagem
Referncias:
- RubyVM::InstructionSequence http://ruby-doc.org/core-2.3.1/RubyVM/InstructionSequence.html
- Inline caching in MRI http://tenderlovemaking.com/2015/12/23/inline-caching-in-mri.html
- Ruby, Trace, Leave, Oh my! http://kgrz.io/2014/04/19/ruby-trace-leave-oh-my.html
Referncias:
- Tail Call Optimization in Ruby http://nithinbekal.com/posts/ruby-tco/
- Tailin' Ruby http://timelessrepo.com/tailin-ruby
- Tail Call Optimization in Ruby: Deep Dive http://blog.tdg5.com/tail-call-optimization-in-ruby-deep-dive/
Referncias:
- TCOMethod Simplifies compiling code with tail call
optimization in MRI Ruby
https://github.com/tdg5/tco_method
- Hamster Efficient, Immutable, Thread-Safe Collection classes
for Ruby
https://github.com/hamstergem/hamster
- Functional Ruby A gem for adding functional programming tools
to Ruby. Inspired by Erlang, Clojure, Haskell, and Functional
Java.
https://github.com/jdantonio/functional-ruby
Obrigado!
gbaptista.com.br
Twitter: @guilhermebps
github.com/gbaptista
linkedin.com/in/guilhermebaptista
Globalcode Open4education
Globalcode Open4education
Recommended