FiberError - 跨线程调用的光纤

时间:2015-03-09 20:36:17

标签: ruby-on-rails ruby fiber

我正在尝试在Rails应用程序中编写一个小功能,该应用程序使用random-word gem生成随机名词,然后将其复数。我第一次访问开发中的页面时能够让它工作,但是我想让脚本在每次加载页面时再次运行。现在,后续页面加载(直到我退回服务器)给我FiberError in WelcomeController#randomwordsfiber called across threads。我试图自己解决这个问题,但我对编程很陌生,并不太了解Fibers的工作原理。我尝试使用Queue,但无法弄清楚如何让它工作,再次因为我不完全理解这个类。我该如何解决这个具体问题?

资料来源:welcome_helper.rb

def random
  noun = RandomWord.nouns.next.split('_').sample.pluralize
  if noun.include? "_"
    noun = noun.split("_").join.pluralize
  else
    noun.pluralize!
  end      
  return noun
end

1 个答案:

答案 0 :(得分:1)

正如您现在可能已经发现的那样,问题是random-word gem不是线程安全的。更准确地说,RandomWord.nounsmodule-level Enumeratoraccessing enumerators across threads is not safe

但是,例如Queue是线程安全的,因此对于此功能的线程安全替代方法,您可以使用nouns.dat from the random-word gem,并在初始化应用程序时随机将其所有单词随机混合到Queue对象中。现在,假设可以通过random_words_queue方法范围内的random访问此队列。然后,您可以将random方法实现为

def random
  unless random_words_queue.empty?
    noun = random_words_queue.pop
    if noun.include? "_"
      noun = noun.split("_").join.pluralize
    else
      noun.pluralize!
    end      
    return noun
  end
end

请注意,如果队列为空,它当前只返回nil,这可能是您不想要的。在这种情况下,您希望它的行为取决于您的要求:

  • 如果有些可预测的词语不是安全问题,并且不太可能惹恼您的用户,那么我会在弹出后立即将noun推到队列的后面。
  • 否则,你应该重新洗牌。

(无论如何,返回nil可能不是任何人想要的。)