Желая убедиться, что мы используем правильную синхронизацию (и не более чем необходимо) при написании потокового кода в JRuby; в частности, в приложении Rails с экземплярами Rails.Использование инициализации threadafe в JRuby gem
ОБНОВЛЕНИЕ: Настоящим образом отредактирован этот вопрос, чтобы быть предельно ясным и использовать последний код, который мы реализуем. Этот код использует жемчужину atomic
, написанную @headius (Charles Nutter) для JRuby, но не уверен, что это абсолютно необходимо или в каких случаях это необходимо для того, что мы пытаемся сделать здесь.
Вот что у нас есть, это излишний (что означает, мы закончили/uber-engineering это) или, может быть, неверно?
ourgem.rb:
require 'atomic' # gem from @headius
SUPPORTED_SERVICES = %w(serviceABC anotherSvc andSoOnSvc).freeze
module Foo
def self.included(cls)
cls.extend(ClassMethods)
cls.send :__setup
end
module ClassMethods
def get(service_name, method_name, *args)
__cached_client(service_name).send(method_name.to_sym, *args)
# we also capture exceptions here, but leaving those out for brevity
end
private
def __client(service_name)
# obtain and return a client handle for the given service_name
# we definitely want to cache the value returned from this method
# **AND**
# it is a requirement that this method ONLY be called *once PER service_name*.
end
def __cached_client(service_name)
@@_clients.value[service_name]
end
def __setup
@@_clients = Atomic.new({})
@@_clients.update do |current_service|
SUPPORTED_SERVICES.inject(Atomic.new({}).value) do |memo, service_name|
if current_services[service_name]
current_services[service_name]
else
memo.merge({service_name => __client(service_name)})
end
end
end
end
end
end
client.rb:
require 'ourgem'
class GetStuffFromServiceABC
include Foo
def self.get_some_stuff
result = get('serviceABC', 'method_bar', 'arg1', 'arg2', 'arg3')
puts result
end
end
Резюме выше: мы имеем @@_clients
(изменяемый переменный класс, держащий Hash клиентов), который мы только хотим заполняйте ONCE для всех доступных сервисов, которые вводятся в ключ для имени службы.
Поскольку хэш в переменном классе (и, следовательно, поточно?), Мы гарантировали, что призыв к __client
не будет работать более чем один раз за имя службы (даже если Пума инстанцирования нескольких потоков с этим классом для обслуживания всех запросов от разных пользователей)? Если переменная класса является потокобезопасной (таким образом), то, возможно, Atomic.new({})
не требуется?
Кроме того, следует ли вместо этого использовать Atomic.new(ThreadSafe::Hash)
? Или снова, разве это не нужно?
Если нет (что означает: вы думаете, мы сделать нужны Atomic.new
сек, по крайней мере, и, возможно, также в ThreadSafe::Hash
), то почему бы не второй (или третий и т.д.) поток прерываний между Atomic.new(nil)
а @@_clients.update do ...
означает, что Atomic.new
s из КАЖДОЙ нити будет КАЖДОЙ создать два (отдельных) объекта?
Благодарим вас за любые советы по безопасности нитей, мы не видим никаких вопросов по SO, которые напрямую касаются этой проблемы.
кажется немного утомительным, но, возможно, не все требования ясны и видны здесь: действительно зависит от использования, как они используются? для первого примера, что такое стек, вызывающий 'initialize', как для второй загрузки/требующей файла, является поточно-безопасным, если вы считаете, что:' @@ _ thrift_client = __thrift_client' ... прекрасно – kares
Спасибо @kares Я отредактировал вопрос значительно. Идея заключается в том, что когда этот класс сначала «включает» в клиенте, мы будем выполнять вызов '__client' * только один раз за одно имя службы. После того, как мы собрали все клиентские дескрипторы обслуживания и кэшировали их, клиент может вызывать эти службы с помощью методов так часто, как им нравится, и мы всегда будем использовать один и тот же дескриптор клиента для каждой другой службы, которую они вызывают.(Если вы хотите знать фон: клиентские дескрипторы - это набор различных сервисов на основе бережливости, которые предоставляются через сервис Zookeeper.) – likethesky
Я хочу указать несколько релевантных ссылок на мой вопрос, один из которых касается [переменные класса и безопасность потоков] (http://stackoverflow.com/questions/9558192/thread-safety-class-variables-in-ruby) и еще один о [потокобезопасных хешах Ruby] (http: // stackoverflow. com/questions/9265879/fast-thread-safe-ruby-hash-with-strong-read-bias), re: этот последний, я бы предпочел использовать версию Java, а не Ruby, так как я использую JRuby уже (и не очень нравится идея использования нестандартного кода для чего-то подобного). Но мой вопрос остается: действительно ли эти методы необходимы? – likethesky