Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Concurrency in Ruby: In search of inspiration

Concurrency in Ruby: In search of inspiration

Concurrency has been a popular topic in the programming community in the last decade and has received special attention in the Ruby community in recent years. José Valim will start his talk by explaining why concurrency has become so important and why it is particularly hard to write safe concurrent software in Ruby, based on his experience from working on Ruby on Rails. The goal of this talk is to highlight the current limitations and start the search for possible solutions, looking at how other languages are tackling this issue today.

Plataformatec

May 31, 2013
Tweet

More Decks by Plataformatec

Other Decks in Technology

Transcript

  1. •Started with Ruby in 2006 •Open Source Contributor •Joined Rails

    Core in 2010 •Author of elixir-lang.org About me
  2. # It finds Rails templates and # caches them in

    between requests class ActionView::Resolver def initialize @cached = Hash.new { ... } end end
  3. Without the GVL, other Ruby implementations may try to change

    the same Hash at the same time, corrupting it
  4. java.util.concurrent ArrayBlockingQueue ConcurrentHashMap ConcurrentLinkedQueue ConcurrentSkipListMap ConcurrentSkipListSet CopyOnWriteArrayList CopyOnWriteArraySet CountDownLatch CyclicBarrier

    DelayQueue Exchanger FutureTask LinkedBlockingDeque LinkedBlockingQueue PriorityBlockingQueue PriorityQueue Semaphore SynchronousQueue
  5. java.util.concurrent ArrayBlockingQueue ConcurrentHashMap ConcurrentLinkedQueue ConcurrentSkipListMap ConcurrentSkipListSet CopyOnWriteArrayList CopyOnWriteArraySet CountDownLatch CyclicBarrier

    DelayQueue Exchanger FutureTask LinkedBlockingDeque LinkedBlockingQueue PriorityBlockingQueue PriorityQueue Semaphore SynchronousQueue ETOOMANYCLASSES
  6. # YARV hash = Hash.new hash.concurrent_read #=> true hash.concurrent_write #=>

    true # JRUBY hash = Hash.new hash.concurrent_read #=> false hash.concurrent_write #=> false # RBX hash = Hash.new hash.concurrent_read #=> ? hash.concurrent_write #=> ?
  7. # When you need thread safety # in any implementation:

    hash = Hash.new hash.concurrent_read! hash.concurrent_write!
  8. class User def initialize @name = AtomicReference.new end def name

    @name.get end def name=(name) @name.set(name) end end
  9. class User def initialize # Provide a default # lazily

    calculated value @name = AtomicReference.new do expensive_calculation end end end
  10. 1. updating instance variables are declared unsafe 2. any thread-safe

    Ruby code needs to treat them as such Proposal #2
  11. 3. implementations like YARV can still provide safe semantics due

    to technical limitation 4. but code that relies on such behavior works by “accident” Proposal #2
  12. Go

  13. Go shows us we can go a long way with

    simple (but powerful) abstractions and great education
  14. is_done = false Thread.new { # do something expensive is_done

    = true # do something else } sleep(0.5) until is_done # a bit more work puts :DONE
  15. done := make(chan bool, 1) go func() { // do

    something expensive done <- true // do something else }() <-done // a bit more work
  16. queue = SizedQueue.new(1) Thread.new { # do something expensive queue

    << true # do something else } queue.pop # a bit more work puts :DONE
  17. select { case <-ch: // a read from ch has

    occurred case <-done: // the done channel is done }
  18. We are also not used to think about concurrency. We

    need more education on how to “think concurrently”
  19. We need... • well-defined semantics • a thread-safe stdlib (example:

    Hash#concurrent_write!) • high-level abstractions & education (example: atomic, queues)
  20. My goal is not to propose final solutions but instigate

    discussion. I hope I have fulfilled it!