-
-
Save wycats/2420126 to your computer and use it in GitHub Desktop.
| class TicketsController < ApplicationController | |
| def show | |
| tickets = params[:tickets].split(",") | |
| ticket_data = tickets.map do |ticket| | |
| parallel { Faraday.get("http://tickets.local/#{ticket}") } | |
| end | |
| render json: { tickets: ticket_data.map(&:result) } | |
| end | |
| end |
| require "future" | |
| module ActionController | |
| module ParallelIO | |
| def parallel(&block) | |
| Future.new(&block) | |
| end | |
| end | |
| end | |
| ActiveSupport.on_load(:action_controller) do | |
| include ActionController::ParallelIO | |
| end |
| require "thread" | |
| class Future | |
| attr_reader :exception, :cancelled | |
| def initialize(&block) | |
| @thread = Thread.new(&block) | |
| @thread.abort_on_exception = false | |
| @exception = nil | |
| @cancelled = false | |
| end | |
| def running? | |
| @thread.alive? | |
| end | |
| def cancelled? | |
| @cancelled | |
| end | |
| def done? | |
| [email protected]? | |
| end | |
| def cancel | |
| @cancelled = true | |
| @thread.kill | |
| end | |
| def result(limit=nil) | |
| value(limit) | |
| rescue Exception => e | |
| @exception = e | |
| nil | |
| end | |
| def exception(limit=nil) | |
| result(limit) | |
| @exception | |
| end | |
| private | |
| def value(limit) | |
| if @thread.join(limit) | |
| @thread.value | |
| else | |
| nil | |
| end | |
| end | |
| end | |
| q = Queue.new | |
| require "uri" | |
| require "net/http" | |
| futures = {} | |
| ["http://www.google.com", "http://www.heroku.com", "http://www.github.com"].each do |url| | |
| futures[url] = Future.new { Net::HTTP.get(URI(url)) } | |
| end | |
| futures["http://www.github.com"].cancel | |
| puts "heroku.com:" | |
| p futures["http://www.heroku.com"].cancelled? | |
| puts futures["http://www.heroku.com"].result | |
| puts futures["http://www.heroku.com"].exception | |
| puts | |
| puts "google.com:" | |
| p futures["http://www.google.com"].cancelled? | |
| puts futures["http://www.google.com"].result | |
| puts futures["http://www.google.com"].exception | |
| puts "github.com:" | |
| p futures["http://www.github.com"].cancelled? | |
| puts futures["http://www.github.com"].result | |
| puts futures["http://www.github.com"].exception |
Concurrent? Yes. Parallel? Not really. Not on MRI at least. Or am I confused about GIL?
In case I am not confused, then possibly fibers would make a better job than threads?
@wycats: Thanks for the gist. May I suggest you provide a quick explanation of the upsides and benefits of such a technique for less technical users? i.e. explain what that code achieves and how exactly one would leverage such a feature in one's code?
@artemave JRuby and Rubinius both support parallel multithreading because they have fine-grained locking models instead of a GIL. So this is extremely relevant to those platforms.
Even on MRI/YARV, you can do parallel blocking I/O, and C extensions can explicitly release the GIL for computationally intensive activities as well.
oh, it is so cool!