Асинхронное программирование с волокнами
em-synchrony оборачивает цикл событий EM в волокне. Хотя намерение состоит в том, чтобы удалить уродство вложенных блоков обратного вызова, это добавило слой путаницы. Я хочу иметь асинхронное программирование, но при этом избегать ошибки "невозможно получить из корневого волокна", возникающей при смешивании вечерних программ и волокон.
Я создал этот код и хотел бы знать, правильное ли мое понимание его работы (я постарался максимально упростить его):
require "eventmachine"
require "em-synchrony"
require "em-synchrony/mysql2"
require "em-synchrony/activerecord"
EM.synchrony do
User.all.each do |user|
Fiber.new {
ImapClient.new(user).check
}.resume
end
end
class ImapClient
attr_accessor :user
def initialize(user)
@user = user
end
def imap_call
client = EM::IMAP.new('imap.gmail.com',993,true)
f = Fiber.current
client.connect.bind! do
client.login(@user.email,@user.password)
end.bind! do
client.select('INBOX')
end.bind! do
client.search(['1:20'])
end.bind! do |ids|
client.fetch(ids, "(UID ENVELOPE BODY[TEXT])")
end.callback do |msgs|
f.resume(msgs)
end.errback do |error|
puts "Connecting or logging in failed: #{error}"
end
return Fiber.yield
end
def check
msgs = imap_call
msgs.each do |msg|
@user.email_messages.create! {body: msg.attr['BODY[TEXT]'], uid: msg.attr['UID']}
end
end
end
1) EM.synchrony оборачивает цикл событий EM (блок кода) в волокне.
2) Делаем асинхронный запрос к базе данных. Предположительно, пока этот запрос выполняется, синхронизация передает управление циклу событий EM, используя Fiber.yield за кулисами.
3) Мы создаем новое волокно для каждой записи пользователя. вызов возобновления выполняет блок кода в новом экземпляре волокна.
4) Выполняем асинхронный вызов IMAP. В ожидании обратного вызова мы выдаем Fiber (который затем позволяет нам проверять электронную почту другого пользователя, используя новое волокно).
5) Когда вызывается обратный вызов, старое волокно возобновляется, и мы проверяем его сообщения.
6) Затем новое волокно продолжается, и это продолжается и продолжается для каждой пользовательской записи.
Это правильно? Я хочу убедиться, что в этом коде нет блокировки.