Ruby разница между объявлением переменной и использованием ее непосредственно в методе - PullRequest
1 голос
/ 28 марта 2020

Если я собираюсь вызвать функцию, скажем, функцию печати, например:

def print(message)
   //... 
end

В чем разница между:

print("Message")

и

message = "Message"
print(message)

Мне любопытно, поскольку ruby - интерпретируемый язык, тогда я не знаю, имеет ли это последствия в управлении памятью или что-то еще.

1 Ответ

2 голосов
/ 28 марта 2020

Несмотря на то, что Ruby широко считается интерпретируемым языком, Ruby частично компилируется в большинстве распространенных реализаций языка. Стандартный интерпретатор (YARV) сначала компилирует ваш исходный код в байт-код, а затем интерпретирует этот байт-код. (Если вы хотите go более подробно об этом топи c, я настоятельно рекомендую Ruby под микроскопом ).

Вы можете использовать RubyVM::InstructionSequence чтобы увидеть байт-код, сгенерированный для определенного Ruby кода. Давайте сравним байт-код для ваших двух примеров:

irb(main):002:0> puts RubyVM::InstructionSequence.compile("print('Message')").dis
asm

== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(1,16)> (catch: FALSE)
0000 putself                                                          (   1)[Li]
0001 putstring                    "Message"
0003 opt_send_without_block       <callinfo!mid:print, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0006 leave
=> nil


irb(main):003:0> puts RubyVM::InstructionSequence.compile("message = 'Message'; print(message)").disasm
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(1,35)> (catch: FALSE)
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] message@0
0000 putstring                    "Message"                           (   1)[Li]
0002 setlocal_WC_0                message@0
0004 putself
0005 getlocal_WC_0                message@0
0007 opt_send_without_block       <callinfo!mid:print, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0010 leave
=> nil

Как мы можем видеть здесь, print('Message') имеет меньше инструкций байт-кода, поэтому, вероятно, будет очень немного быстрее (не достаточно быстрее, чтобы жертвовать ясностью при написании кода). Кроме того, print('Message') не использует локальные переменные, поэтому для этого фрагмента не требуется таблица локальных переменных.

В вашем примере message = 'Message'; print(message) имеется больше инструкций с байт-кодом, поскольку для него требуется установить и получить локальную переменную и впоследствии также требуется таблица локальных переменных (показана как local table (size: 1, ...)). Это означает, что это займет немного больше памяти.

Несмотря на два разных подхода, вы все равно создаете один и тот же объект - строку 'Message'. Из-за этого на сборщик мусора мало влияет, как мы можем видеть из значения GC.stat: (a.rb не использует local, а b.rb -)

$ ruby a.rb                                                                                                        
Message{:count=>12, :heap_allocated_pages=>51, :heap_sorted_length=>62, :heap_allocatable_pages=>11, :heap_available_slots=>20791, :heap_live_slots=>20530, :heap_free_slots=>261, :heap_final_slots=>0, :heap_marked_slots=>15224, :heap_eden_pages=>51, :heap_tomb_pages=>0, :total_allocated_pages=>51, :total_freed_pages=>0, :total_allocated_objects=>68286, :total_freed_objects=>47756, :malloc_increase_bytes=>374152, :malloc_increase_bytes_limit=>16777216, :minor_gc_count=>9, :major_gc_count=>3, :remembered_wb_unprotected_objects=>213, :remembered_wb_unprotected_objects_limit=>424, :old_objects=>14957, :old_objects_limit=>29920, :oldmalloc_increase_bytes=>431824, :oldmalloc_increase_bytes_limit=>16777216}%

$ ruby b.rb                                                                                                        
Message{:count=>12, :heap_allocated_pages=>51, :heap_sorted_length=>62, :heap_allocatable_pages=>11, :heap_available_slots=>20785, :heap_live_slots=>20518, :heap_free_slots=>267, :heap_final_slots=>0, :heap_marked_slots=>15209, :heap_eden_pages=>51, :heap_tomb_pages=>0, :total_allocated_pages=>51, :total_freed_pages=>0, :total_allocated_objects=>68288, :total_freed_objects=>47770, :malloc_increase_bytes=>374488, :malloc_increase_bytes_limit=>16777216, :minor_gc_count=>9, :major_gc_count=>3, :remembered_wb_unprotected_objects=>213, :remembered_wb_unprotected_objects_limit=>424, :old_objects=>14956, :old_objects_limit=>29918, :oldmalloc_increase_bytes=>434104, :oldmalloc_increase_bytes_limit=>16777216}

The * Клавиша 1024 * показывает количество раз, которое запускался сборщик мусора, и он одинаков для обоих ваших примеров, поэтому он не влияет на сборку мусора.

...