如何加速我的Ruby应用程序?

时间:2009-08-20 05:26:49

标签: ruby-on-rails multithreading performance fork

我正在制作一个我正在尝试优化的数据密集型Web应用程序。我听说过分叉和线程,但我不知道它们是否适用于我想要做的事情,如果是的话,如何实现它们。我的代码如下所示:

  def search
      @amazon_data=Hash.from_xml(item.retrieve_amazon(params[:sku]))
        unless @amazon_data['results'] == nil
          @amazon_data['results']['item'].size.times do |i|
            @all_books << { :vendor => 'Amazon.com',
                            :price => @amazon_data['results']['item'][i]['price'].to_f,
                            :shipping => @amazon_data['results']['item'][i]['ship'].to_f,
                            :condition => @amazon_data['results']['item'][i]['condition'],
                            :total => @amazon_data['results']['item'][i]['price'].to_f + @amazon_data['results']['item'][i]['ship'].to_f,
                            :availability => 'In Stock',
                            :link_text => 'Go to Amazon.com',
                            :link_url => "http://www.amazon.com/gp/offer-listing/#{params[:isbn]}"
            }
        end
      end
       @ebay_data=Hash.from_xml(Book.retrieve_ebay(params[:sku]))
        unless @ebay_data['results'] == nil
          @ebay_data['results']['item'].size.times do |i|
            @all_books << { :vendor => 'eBay',
                            :price => @ebay_data['results']['item'][i]['price'].to_f,
                            :shipping => @ebay_data['results']['item'][i]['ship'].to_f,
                            :condition => 'Used',
                            :total => @ebay_data['results']['item'][i]['price'].to_f + @ebay_data['results']['item'][i]['ship'].to_f,
                            :availability => 'In Stock',
                            :link_text => 'Go to eBay',
                            :link_url => "http://www.amazon.com/gp/offer-listing/#{params[:sku]}"
            }
        end
    end
  end

所以,基本上我所拥有的是两个从eBay和亚马逊中检索数据并在此处解析的行为。我怎样才能同时运行这两个动作?叉子或线程与我想要完成的任务有关吗?


这会将API时间缩短一半,但我不知道如何返回结果。在返回API结果之前加载后续视图....但是它返回数据。当我编码

puts @all_books  
线程内的

结果显示在控制台中。但是,在线程之外,不会返回结果。

def search
    Thread.new do
      @amazon_data=Hash.from_xml(item.retrieve_amazon(params[:sku]))
        unless @amazon_data['results'] == nil
          @amazon_data['results']['item'].size.times do |i|
            @all_books << { :vendor => 'Amazon.com',
                            :price => @amazon_data['results']['item'][i]['price'].to_f,
                            :shipping => @amazon_data['results']['item'][i]['ship'].to_f,
                            :condition => @amazon_data['results']['item'][i]['condition'],
                            :total => @amazon_data['results']['item'][i]['price'].to_f + @amazon_data['results']['item'][i]['ship'].to_f,
                            :availability => 'In Stock',
                            :link_text => 'Go to Amazon.com',
                            :link_url => "http://www.amazon.com/gp/offer-listing/#{params[:isbn]}"
            }
        end
      end
     end
    Thread.new do
       @ebay_data=Hash.from_xml(Book.retrieve_ebay(params[:sku]))
        unless @ebay_data['results'] == nil
          @ebay_data['results']['item'].size.times do |i|
            @all_books << { :vendor => 'eBay',
                            :price => @ebay_data['results']['item'][i]['price'].to_f,
                            :shipping => @ebay_data['results']['item'][i]['ship'].to_f,
                            :condition => 'Used',
                            :total => @ebay_data['results']['item'][i]['price'].to_f + @ebay_data['results']['item'][i]['ship'].to_f,
                            :availability => 'In Stock',
                            :link_text => 'Go to eBay',
                            :link_url => "http://www.amazon.com/gp/offer-listing/#{params[:sku]}"
            }
        end
      end
    end
  end

我是否在正确的轨道上?如何从线程中返回结果?是变量只能在线程中访问,还是问题在于程序在返回结果之前进展?


不幸的是,应用程序需要实时用户输入来查询API。返回的数据需要新鲜,因为它与市场中的产品定价有关...例如,用户将输入SKU并且该信息将通过该信息向适用的站点发出请求(在这种情况下,亚马逊和eBay) 。)目前它向亚马逊提出请求,解析数据,格式化,然后转移到eBay,解析数据并格式化。然后格式化的数据显示在视图中。

我的想法是,如果我可以同时进行这些API调用(在不同的线程上?),它将节省Web服务端的时间,因为所需要的只是解析返回的数据并正确格式化。 (我也可能加快......)

3 个答案:

答案 0 :(得分:1)

是的,在这种情况下,我仍然认为你的工作安排会更好。这样的动作可以执行的绝对最快的是两个API请求的较慢 - 并且您无法保证网络延迟,远程API上的负载等。另一方面,您必须实施一些Javascript代码以定期轮询以检测作业完成情况并通知用户结果。

另外,ruby 1.8中的线程行为有时候会有点时髦,特别是在规模上,所以要小心。

答案 1 :(得分:0)

没有更多信息很难说,但我怀疑等待API响应是花费大部分时间的地方。

尝试不同的方法,其中API响应的请求和处理在与Web服务流程不同的过程中处理。前端代码可能必须定期轮询结果,并将操作结果注入页面。但胜利是整个请求都没有得到备份,等待亚马逊和Ebay做他们的事情。

有几个插件可以提供帮助,delayed_job是一个很好的起点。

答案 2 :(得分:0)

您还可以查看EventMachine,它允许您以非阻塞方式执行出站网络呼叫。如果你可以将第一个结果返回给用户,通过ajax获得最终结果,用户交互会感觉更快。

这与Kayak.com的实时航班搜索类似。

您还可以考虑缓存结果,快速将结果返回给用户,然后通过ajax填充更新的结果(您加载的异步)。 (你必须弄清楚正确的用户界面,也许只是将'热门'结果放在首位,然后将最新的更新放在首屏下面)

* EventMachine很复杂