Для чего нужен Thread.current в примере DCI в Ruby?
Что такое Thread.current
в этом коде? Я смотрю на этот пример использования DCI в приложении Rails. В lib/context.rb есть это:
module Context
include ContextAccessor
def context=(ctx)
Thread.current[:context] = ctx
end
def in_context
old_context = self.context
self.context = self
res = yield
self.context = old_context
res
end
end
который используется в различных контекстах в приложении / контекстах, например:
def bid
in_context do
validator.validate
biddable.create_bid
end
#...
end
В чем преимущество запуска кода в in_context
заблокировать и установить пару ключ-значение в текущем потоке?
2 ответа
Как правило, внутри блока у вас нет доступа к контексту вызывающего (кроме переменных закрытия).
▶ class A
▷ attr_accessor :a
▷ def test
▷ yield if block_given?
▷ end
▷ end
#⇒ :test
▶ inst = A.new
#⇒ #<A:0x00000006f41e28>
▶ inst.a = 'Test'
#⇒ "Test"
▶ inst.test do
▷ puts self
▷ # here you do not have an access to inst at all
▷ # this would raise an exception: puts self.a
▷ end
#⇒ main
Но с контекстом у вас все еще может быть доступ к inst
изнутри блока:
▶ in_context do
▷ puts self.context.a
▷ end
#⇒ 'Test'
Итак, можно представить proc
(рассмотреть оба A
а также B
иметь Context
в комплекте):
▶ pr = ->() { puts self.context }
▶ A.new.in_context &pr
#⇒ #<A:0x00000006f41e28>
▶ B.new.in_context &pr
#⇒ #<B:0x00000006f41eff>
Сейчас внешний proc
pr
имеет практически полный доступ к своему абоненту.
Thread.current
требуется для поддержки многопоточного приложения, где каждый поток имеет свой собственный контекст.
Существует также ContextAccessor
модуль включен, где каждый получает контекст. Соединение их просто дает более четкую картину:
# context.rb
def context=(ctx)
Thread.current[:context] = ctx
end
# context_accessor.rb
def context
Thread.current[:context]
end
in_context
Метод предназначен для безопасного изменения контекста внутри своего блока. Какими бы ни были изменения, старый контекст восстанавливается, когда блок заканчивает выполнение.