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

In the Back of Your Mind

jeg2
February 08, 2012

In the Back of Your Mind

Some simple examples of how to pipeline data through beanstalkd or 0MQ, using Dominic memory encoding as an example.

jeg2

February 08, 2012
Tweet

More Decks by jeg2

Other Decks in Programming

Transcript

  1. MEMORY TECHNIQUES • The book includes various techniques for improving

    memory • It helps to translate abstract data (the brain is weak with) into vivid images (a strength of the brain)
  2. MEMORY TECHNIQUES • The book includes various techniques for improving

    memory • It helps to translate abstract data (the brain is weak with) into vivid images (a strength of the brain) • The Dominic System is used to translate numbers into characters and actions • It can help you memorize large numbers
  3. SINGLE DIGITS • Just count through the alphabet • But

    replace F with S • And skip to N when you hit 9
  4. SINGLE DIGITS • Just count through the alphabet • But

    replace F with S • And skip to N when you hit 9 1 2 3 4 5 6 7 8 9 0 A B C D E S G H N O
  5. DOUBLE DIGITS • Convert digit pairs into letters • 15

    = AE, 23 = BC, 27 = BG, 39 = CN, 80 = HO, 80 = HA
  6. DOUBLE DIGITS • Convert digit pairs into letters • 15

    = AE, 23 = BC, 27 = BG, 39 = CN, 80 = HO, 80 = HA • Use the letters as initials for a character • AE = Albert Einstein, BG = Bill Gates, CN = Chuck Norris
  7. DOUBLE DIGITS • Convert digit pairs into letters • 15

    = AE, 23 = BC, 27 = BG, 39 = CN, 80 = HO, 80 = HA • Use the letters as initials for a character • AE = Albert Einstein, BG = Bill Gates, CN = Chuck Norris • Or use letters to indicate characters in other ways • BC = Jesus Christ, HO = Santa Claus, HA = Julia Sweeney
  8. IMAGERY IS KEY • Each digit pair should create an

    image in your mind • The image need to be a character doing their signature action • Chuck Norris performing a roundhouse kick • Santa Claus delivering presents • Julia Sweeney dressing asexually
  9. FOUR DIGIT NUMBERS • To handle four digit numbers, use

    the first two for the character and the second two as the action • 2339 = BCCN = Jesus Christ performing a roundhouse kick • 8081 = HOHA = Santa Claus dressing asexually
  10. FOUR DIGIT NUMBERS • To handle four digit numbers, use

    the first two for the character and the second two as the action • 2339 = BCCN = Jesus Christ performing a roundhouse kick • 8081 = HOHA = Santa Claus dressing asexually • You’re up to a 10,000 number memory at this point!
  11. LARGER NUMBERS • “Chunk” up bigger numbers into two and

    four digit groups • Build wacky stories using those characters and actions • 27808039 = 2780 8039 = BGHO HOCN = Bill Gates started delivering presents, but this angered Santa Claus who gave him a roundhouse kick.
  12. A CAST OF CHARACTERS http://ron.ludism.org/mnemonics_public.txt … 40 = DO =

    Fred Flintstone, breaking rocks in the quarry (Yabba dabba DOo!) 41 = DA = Douglas Adams, putting a Babelfish into his ear (_The Hitch Hiker's Guide to the Galaxy_) 42 = DB = PERSONAL 43 = DC = George Washington, chopping down cherry tree (Washington DC) 44 = DD = Danny Dunn (fictional character), descending in a bathysphere 45 = DE = PERSONAL 46 = DS = Ivan Stang (a.k.a. Doug Smith), ranting on a soapbox 47 = DG = PERSONAL 48 = DH = Douglas Hofstadter, recursively holding a picture of himself 49 = DN = Dan (_Roseanne_ TV show), wearing sunglasses to switch on Christmas lights …
  13. A CAST OF CHARACTERS http://ron.ludism.org/mnemonics_public.txt … 40 = DO =

    Fred Flintstone, breaking rocks in the quarry (Yabba dabba DOo!) 41 = DA = Douglas Adams, putting a Babelfish into his ear (_The Hitch Hiker's Guide to the Galaxy_) 42 = DB = PERSONAL 43 = DC = George Washington, chopping down cherry tree (Washington DC) 44 = DD = Danny Dunn (fictional character), descending in a bathysphere 45 = DE = PERSONAL 46 = DS = Ivan Stang (a.k.a. Doug Smith), ranting on a soapbox 47 = DG = PERSONAL 48 = DH = Douglas Hofstadter, recursively holding a picture of himself 49 = DN = Dan (_Roseanne_ TV show), wearing sunglasses to switch on Christmas lights …
  14. BEANSTALKD • A simple but highly effective message queue •

    I’ve used it many times, including to do moves in Go vs Go
  15. BEANSTALKD • A simple but highly effective message queue •

    I’ve used it many times, including to do moves in Go vs Go • It’s definitely one of my favorite tools for background jobs
  16. CHARACTER LOOKUPS require "open-uri" def lookup_table return @lookup_table if defined?

    @lookup_table @lookup_table = { } open("http://ron.ludism.org/mnemonics_public.txt") do |page| page.each do |line| if line =~ /\A(\d{2})\s*=\s*[A-Z]{2}\s*=\s*(.+)/ @lookup_table[$1] = $2 elsif line =~ /\A\s+(.+)/ @lookup_table.values.last << " #{$1}" end end end @lookup_table end
  17. CHARACTER LOOKUPS require "open-uri" def lookup_table return @lookup_table if defined?

    @lookup_table @lookup_table = { } open("http://ron.ludism.org/mnemonics_public.txt") do |page| page.each do |line| if line =~ /\A(\d{2})\s*=\s*[A-Z]{2}\s*=\s*(.+)/ @lookup_table[$1] = $2 elsif line =~ /\A\s+(.+)/ @lookup_table.values.last << " #{$1}" end end end @lookup_table end
  18. CHARACTER LOOKUPS require "open-uri" def lookup_table return @lookup_table if defined?

    @lookup_table @lookup_table = { } open("http://ron.ludism.org/mnemonics_public.txt") do |page| page.each do |line| if line =~ /\A(\d{2})\s*=\s*[A-Z]{2}\s*=\s*(.+)/ @lookup_table[$1] = $2 elsif line =~ /\A\s+(.+)/ @lookup_table.values.last << " #{$1}" end end end @lookup_table end
  19. ENCODING CHUNKS def encode(n, as = :both) if n.size ==

    4 and as == :both "#{encode(n[0..1], :character)} #{encode(n[2..3], :action)}." elsif as == :both "#{encode(n, :character)} #{encode(n, :action)}." elsif as == :character lookup_table[n][/\A\s*([^,]+(?:\([^)]+\))?)/, 1] elsif as == :action lookup_table[n][/\A\s*[^,]+(?:\([^)]+\))?,\s*(.+?)\s*\z/, 1] end end
  20. ENCODING CHUNKS def encode(n, as = :both) if n.size ==

    4 and as == :both "#{encode(n[0..1], :character)} #{encode(n[2..3], :action)}." elsif as == :both "#{encode(n, :character)} #{encode(n, :action)}." elsif as == :character lookup_table[n][/\A\s*([^,]+(?:\([^)]+\))?)/, 1] elsif as == :action lookup_table[n][/\A\s*[^,]+(?:\([^)]+\))?,\s*(.+?)\s*\z/, 1] end end
  21. ENCODING CHUNKS def encode(n, as = :both) if n.size ==

    4 and as == :both "#{encode(n[0..1], :character)} #{encode(n[2..3], :action)}." elsif as == :both "#{encode(n, :character)} #{encode(n, :action)}." elsif as == :character lookup_table[n][/\A\s*([^,]+(?:\([^)]+\))?)/, 1] elsif as == :action lookup_table[n][/\A\s*[^,]+(?:\([^)]+\))?,\s*(.+?)\s*\z/, 1] end end
  22. ENCODING NUMBERS job "number.encode" do |args| number = args["number"].to_s.delete("^0-9") number

    = "0#{number}" if (number.size % 2).nonzero? chunks = [4] * (number.size / 4) + [2] * (number.size % 4 / 2) encodings = [ ] chunks.permutation.to_a.uniq.each do |grouping| encodings << number.match(/\A#{grouping.map { |g| "(.{#{g}})" }.join}\z/) .captures .map { |n| encode(n) } .join(" ") .tr("_", '"') end Stalker.enqueue( "number.display", number: args["number"], encodings: encodings ) end
  23. ENCODING NUMBERS job "number.encode" do |args| number = args["number"].to_s.delete("^0-9") number

    = "0#{number}" if (number.size % 2).nonzero? chunks = [4] * (number.size / 4) + [2] * (number.size % 4 / 2) encodings = [ ] chunks.permutation.to_a.uniq.each do |grouping| encodings << number.match(/\A#{grouping.map { |g| "(.{#{g}})" }.join}\z/) .captures .map { |n| encode(n) } .join(" ") .tr("_", '"') end Stalker.enqueue( "number.display", number: args["number"], encodings: encodings ) end
  24. ENCODING NUMBERS job "number.encode" do |args| number = args["number"].to_s.delete("^0-9") number

    = "0#{number}" if (number.size % 2).nonzero? chunks = [4] * (number.size / 4) + [2] * (number.size % 4 / 2) encodings = [ ] chunks.permutation.to_a.uniq.each do |grouping| encodings << number.match(/\A#{grouping.map { |g| "(.{#{g}})" }.join}\z/) .captures .map { |n| encode(n) } .join(" ") .tr("_", '"') end Stalker.enqueue( "number.display", number: args["number"], encodings: encodings ) end
  25. ENCODING NUMBERS job "number.encode" do |args| number = args["number"].to_s.delete("^0-9") number

    = "0#{number}" if (number.size % 2).nonzero? chunks = [4] * (number.size / 4) + [2] * (number.size % 4 / 2) encodings = [ ] chunks.permutation.to_a.uniq.each do |grouping| encodings << number.match(/\A#{grouping.map { |g| "(.{#{g}})" }.join}\z/) .captures .map { |n| encode(n) } .join(" ") .tr("_", '"') end Stalker.enqueue( "number.display", number: args["number"], encodings: encodings ) end
  26. RUNNING JOBS $ beanstalkd $ ruby encode_number.rb 405-285-0536 $ rvm

    1.9.2 $ RUBYLIB=. stalk jobs.rb number.encode [2010-12-08 13:07:24 -0600] Working 1 jobs: [ number.encode ] [2010-12-08 13:11:18 -0600] -> number.encode (number=405-285-0536) [2010-12-08 13:11:19 -0600] -> number.encode finished in 510ms
  27. RUNNING JOBS $ beanstalkd $ ruby encode_number.rb 405-285-0536 $ rvm

    1.9.2 $ RUBYLIB=. stalk jobs.rb number.encode [2010-12-08 13:07:24 -0600] Working 1 jobs: [ number.encode ] [2010-12-08 13:11:18 -0600] -> number.encode (number=405-285-0536) [2010-12-08 13:11:19 -0600] -> number.encode finished in 510ms
  28. RUNNING JOBS $ beanstalkd $ ruby encode_number.rb 405-285-0536 $ rvm

    1.9.2 $ RUBYLIB=. stalk jobs.rb number.encode [2010-12-08 13:07:24 -0600] Working 1 jobs: [ number.encode ] [2010-12-08 13:11:18 -0600] -> number.encode (number=405-285-0536) [2010-12-08 13:11:19 -0600] -> number.encode finished in 510ms
  29. RUNNING JOBS $ beanstalkd $ ruby encode_number.rb 405-285-0536 $ rvm

    1.9.2 $ RUBYLIB=. stalk jobs.rb number.encode [2010-12-08 13:07:24 -0600] Working 1 jobs: [ number.encode ] [2010-12-08 13:11:18 -0600] -> number.encode (number=405-285-0536) [2010-12-08 13:11:19 -0600] -> number.encode finished in 510ms
  30. RUNNING JOBS $ beanstalkd $ ruby encode_number.rb 405-285-0536 $ rvm

    1.9.2 $ RUBYLIB=. stalk jobs.rb number.encode [2010-12-08 13:07:24 -0600] Working 1 jobs: [ number.encode ] [2010-12-08 13:11:18 -0600] -> number.encode (number=405-285-0536) [2010-12-08 13:11:19 -0600] -> number.encode finished in 510ms
  31. RUNNING JOBS $ beanstalkd $ ruby encode_number.rb 405-285-0536 $ rvm

    1.9.2 $ RUBYLIB=. stalk jobs.rb number.encode [2010-12-08 13:07:24 -0600] Working 1 jobs: [ number.encode ] [2010-12-08 13:11:18 -0600] -> number.encode (number=405-285-0536) [2010-12-08 13:11:19 -0600] -> number.encode finished in 510ms
  32. RUNNING JOBS $ beanstalkd $ ruby encode_number.rb 405-285-0536 $ rvm

    1.9.2 $ RUBYLIB=. stalk jobs.rb number.encode [2010-12-08 13:07:24 -0600] Working 1 jobs: [ number.encode ] [2010-12-08 13:11:18 -0600] -> number.encode (number=405-285-0536) [2010-12-08 13:11:19 -0600] -> number.encode finished in 510ms $ RUBYLIB=. stalk jobs.rb number.display … 405-285-0536: Fred Flintstone breaking rocks in the quarry (Yabba dabba DOo!). Stuart Little (tiny fictional mouse wearing street clothes) releasing helium balloons (Newtonmas, HE HE HE!). J.R.R. Tolkien stepping into the Wardrobe. …
  33. BEANSTALKD PROS • Extremely lightweight (especially if you drop the

    Rails stack) • Ridiculously fast • Designed to be a queue
  34. BEANSTALKD PROS • Extremely lightweight (especially if you drop the

    Rails stack) • Ridiculously fast • Designed to be a queue • “Tubes” make it trivial to divide work or pipeline jobs
  35. BEANSTALKD PROS • Extremely lightweight (especially if you drop the

    Rails stack) • Ridiculously fast • Designed to be a queue • “Tubes” make it trivial to divide work or pipeline jobs • Really easy to spread across ruby versions and environments
  36. BEANSTALKD CONS • Not ideal for durable queuing needs (though

    it does have a binlog) • Missing niceties like logging (though Stalker adds logging above beanstalkd)
  37. BEANSTALKD CONS • Not ideal for durable queuing needs (though

    it does have a binlog) • Missing niceties like logging (though Stalker adds logging above beanstalkd) • Needs job introspection
  38. 0MQ

  39. 0MQ • A high-level socket API over an asynchronous message

    queue • Request and reply, publish subscribe, and pipeline models
  40. 0MQ • A high-level socket API over an asynchronous message

    queue • Request and reply, publish subscribe, and pipeline models • This was my first time using it (I was curious about it) • I don’t think it’s well suited to this task
  41. THE END OF THE PIPELINE require "zmq" zmq = ZMQ::Context.new

    up = zmq.socket(ZMQ::UPSTREAM) up.bind("tcp://127.0.0.1:5000") while message = up.recv puts message end
  42. THE END OF THE PIPELINE require "zmq" zmq = ZMQ::Context.new

    up = zmq.socket(ZMQ::UPSTREAM) up.bind("tcp://127.0.0.1:5000") while message = up.recv puts message end
  43. THE END OF THE PIPELINE require "zmq" zmq = ZMQ::Context.new

    up = zmq.socket(ZMQ::UPSTREAM) up.bind("tcp://127.0.0.1:5000") while message = up.recv puts message end
  44. THE END OF THE PIPELINE require "zmq" zmq = ZMQ::Context.new

    up = zmq.socket(ZMQ::UPSTREAM) up.bind("tcp://127.0.0.1:5000") while message = up.recv puts message end
  45. NUMBER LOOKUPS # same lookup_table() as before… def lookup lookup_table.each

    do |number, character_and_action| return number if yield character_and_action end nil end def character_number(msg) lookup { |ca| msg.start_with? ca[/\A\s*([^,]+(?:\([^)]+\))?)/, 1] } end def action_number(msg) lookup { |ca| msg.end_with? ca[/\A\s*[^,]+(?:\([^)]+\))?,\s*(.+?)\s*\z/, 1] } end
  46. NUMBER LOOKUPS # same lookup_table() as before… def lookup lookup_table.each

    do |number, character_and_action| return number if yield character_and_action end nil end def character_number(msg) lookup { |ca| msg.start_with? ca[/\A\s*([^,]+(?:\([^)]+\))?)/, 1] } end def action_number(msg) lookup { |ca| msg.end_with? ca[/\A\s*[^,]+(?:\([^)]+\))?,\s*(.+?)\s*\z/, 1] } end
  47. A DECODER def decode(message) message.to_s.strip.split(/\.(?:\s{2}|\n|\z)/).map { |chunk| chunk.gsub!(/\s+/, " ")

    character = character_number(chunk) action = action_number(chunk) character == action ? character : "#{character}#{action}" }.join end
  48. THE MIDDLE PIPE require "zmq" zmq = ZMQ::Context.new up =

    zmq.socket(ZMQ::UPSTREAM) down = zmq.socket(ZMQ::DOWNSTREAM) up.bind("tcp://127.0.0.1:5001") down.connect("tcp://127.0.0.1:5000") while message = up.recv down.send(decode(message)) end
  49. THE MIDDLE PIPE require "zmq" zmq = ZMQ::Context.new up =

    zmq.socket(ZMQ::UPSTREAM) down = zmq.socket(ZMQ::DOWNSTREAM) up.bind("tcp://127.0.0.1:5001") down.connect("tcp://127.0.0.1:5000") while message = up.recv down.send(decode(message)) end
  50. THE MIDDLE PIPE require "zmq" zmq = ZMQ::Context.new up =

    zmq.socket(ZMQ::UPSTREAM) down = zmq.socket(ZMQ::DOWNSTREAM) up.bind("tcp://127.0.0.1:5001") down.connect("tcp://127.0.0.1:5000") while message = up.recv down.send(decode(message)) end
  51. THE MIDDLE PIPE require "zmq" zmq = ZMQ::Context.new up =

    zmq.socket(ZMQ::UPSTREAM) down = zmq.socket(ZMQ::DOWNSTREAM) up.bind("tcp://127.0.0.1:5001") down.connect("tcp://127.0.0.1:5000") while message = up.recv down.send(decode(message)) end
  52. THE PIPELINE OPENING require "zmq" zmq = ZMQ::Context.new down =

    zmq.socket(ZMQ::DOWNSTREAM) down.connect("tcp://127.0.0.1:5001") down.send(ARGF.read)
  53. A DATA PIPELINE IN ACTION $ ruby queue_message.rb Fred Flintstone

    breaking rocks in the quarry (Yabba dabba DOo!). Stuart Little (tiny fictional mouse wearing street clothes) releasing helium balloons (Newtonmas, HE HE HE!). J.R.R. Tolkien stepping into the Wardrobe. ^d
  54. A DATA PIPELINE IN ACTION $ ruby queue_message.rb Fred Flintstone

    breaking rocks in the quarry (Yabba dabba DOo!). Stuart Little (tiny fictional mouse wearing street clothes) releasing helium balloons (Newtonmas, HE HE HE!). J.R.R. Tolkien stepping into the Wardrobe. ^d $ ruby decoder.rb
  55. A DATA PIPELINE IN ACTION $ ruby queue_message.rb Fred Flintstone

    breaking rocks in the quarry (Yabba dabba DOo!). Stuart Little (tiny fictional mouse wearing street clothes) releasing helium balloons (Newtonmas, HE HE HE!). J.R.R. Tolkien stepping into the Wardrobe. ^d $ ruby decoder.rb $ ruby decoder_display.rb 4052850536
  56. 0MQ PROS • Asynchronous messaging primitives for constructing networks •

    Extremely versatile (can be made to fit most any model)
  57. 0MQ PROS • Asynchronous messaging primitives for constructing networks •

    Extremely versatile (can be made to fit most any model) • Supports many to many connections
  58. 0MQ PROS • Asynchronous messaging primitives for constructing networks •

    Extremely versatile (can be made to fit most any model) • Supports many to many connections • Automatically load balanced
  59. 0MQ CONS • Very low-level (really just a platform to

    build on) • Missing all the conveniences: logging, message formats, etc.
  60. 0MQ CONS • Very low-level (really just a platform to

    build on) • Missing all the conveniences: logging, message formats, etc. • Best for asynchronous networks you design and build