Share
Embed
CONCURRENCY PATTERNS IN RUBYMOTION
my #inspect2013 Talk on iOS Concurrency patterns
using Grand Central Dispatch and/or NSOperationQueue
.mateus
March 30, 2013
Transcript
78 slides
-
#inspect Mateus Armando MacRuby enthusiastic Rubymotion early adopter Mobile OS
Obsessed Deutsche Telekom AG Who Am I? 2 Samstag, 30. März 13 -
#inspect Race Conditions if has_due == true pay_my_dues() has_due =
false end 7 Samstag, 30. März 13 -
#inspect Race Conditions if has_due == true pay_my_dues() has_due =
false end 7 Samstag, 30. März 13 -
#inspect Race Conditions if has_due == true pay_my_dues() has_due =
false end 7 Samstag, 30. März 13 -
#inspect Race Conditions if has_due == true pay_my_dues() has_due =
false end 7 Samstag, 30. März 13 -
#inspect Race Conditions if has_due == true pay_my_dues() has_due =
false end 7 Samstag, 30. März 13 -
#inspect Terminology Parallelism: making programs run faster by using more
hardware like multiple CPU or GPU cores Concurrency: ways of structuring programs into independent activities that can communicate and synchronise with each other Parallelism ≠ Concurrency 8 Samstag, 30. März 13 -
#inspect Dispatch::Queue lambda {...} lambda {...} lambda {...} lambda {...}
12 Samstag, 30. März 13 -
#inspect GCD-How does it work Task Task Task Thread Thread
13 Samstag, 30. März 13 -
#inspect GCD-How does it work Task Task Task Task Thread
Thread Thread 13 Samstag, 30. März 13 -
#inspect GCD-How does it work Task Task Task Task Thread
Thread Thread 13 Samstag, 30. März 13 -
#inspect GCD-How does it work Task Task Task Task Thread
Thread Thread 13 Samstag, 30. März 13 -
#inspect Queue Task Task Task Task Execute tasks one at
a time First-in, First-out (FIFO) order very lightweight (~160 bytes) can replace lock and mutexes Serial Queues 14 Samstag, 30. März 13 -
#inspect Queue Task Task Task Task Execute tasks one at
a time First-in, First-out (FIFO) order very lightweight (~160 bytes) can replace lock and mutexes Serial Queues 14 Samstag, 30. März 13 -
#inspect Queue Task Task Task Task Execute tasks one at
a time First-in, First-out (FIFO) order very lightweight (~160 bytes) can replace lock and mutexes Serial Queues 14 Samstag, 30. März 13 -
#inspect Serial Queues queue = Dispatch::Queue.new(“org.comp.app.task”) def status=(new_status) @queue.sync {
@status = new_status } end def status @queue.sync { return @status } end 16 Samstag, 30. März 13 -
#inspect @queue.sync do Race Conditions if has_due == true pay_my_dues()
has_due = false end end 17 Samstag, 30. März 13 -
#inspect Queue Concurrent Queues Task Task Task Task ๏ may
execute tasks simultaneously ๏ no guarantee for the execution order ๏ magic! 18 Samstag, 30. März 13 -
#inspect Queue Concurrent Queues Task Task Task Task ๏ may
execute tasks simultaneously ๏ no guarantee for the execution order ๏ magic! 18 Samstag, 30. März 13 -
#inspect Queue Concurrent Queues Task Task Task Task ๏ may
execute tasks simultaneously ๏ no guarantee for the execution order ๏ magic! 18 Samstag, 30. März 13 -
#inspect queue = Dispatch::Queue.concurrent(:background) queue = Dispatch::Queue.concurrent(:low) queue = Dispatch::Queue.concurrent(:default)
Concurrent Queues 19 Samstag, 30. März 13 -
#inspect queue = Dispatch::Queue.concurrent(:background) queue = Dispatch::Queue.concurrent(:low) queue = Dispatch::Queue.concurrent(:default)
queue = Dispatch::Queue.concurrent(:high) Concurrent Queues 19 Samstag, 30. März 13 -
#inspect queue = Dispatch::Queue.concurrent(:background) queue = Dispatch::Queue.concurrent(:low) queue = Dispatch::Queue.concurrent(:default)
queue = Dispatch::Queue.concurrent(:high) Concurrent Queues 19 Samstag, 30. März 13 -
#inspect queue = Dispatch::Queue.concurrent(:background) queue = Dispatch::Queue.concurrent(:low) queue = Dispatch::Queue.concurrent(:default)
queue = Dispatch::Queue.concurrent(:high) Concurrent Queues 19 Samstag, 30. März 13 -
#inspect queue = Dispatch::Queue.concurrent(“org.task”) queue = Dispatch::Queue.concurrent(:background) queue = Dispatch::Queue.concurrent(:low)
queue = Dispatch::Queue.concurrent(:default) queue = Dispatch::Queue.concurrent(:high) Concurrent Queues 19 Samstag, 30. März 13 -
#inspect Concurrent Queues queue = Dispatch::Queue.concurrent('de.mateus.example') queue.async do puts "Hi
There!" end queue.async do puts "Good Bye" end 20 Samstag, 30. März 13 -
#inspect Barriers queue = Dispatch::Queue.concurrent('de.mateus.example') queue.async do puts "Hi There!"
end queue.barrier_async do puts "Good Bye" end 22 Samstag, 30. März 13 -
#inspect Dispatch::Groups queue = Dispatch::Queue.concurrent('de.mateus.example') group = Dispatch::Group.new queue.async(group) do
time = Time.now puts "Hi There! #{time}" end group.wait queue.async do puts "Good Bye" end 23 Samstag, 30. März 13 -
#inspect Dispatch.once Upon A Time - Executes a block object
once and only once in your app lifetime please don’t use it for UITableView cell layout :-) at least in Rubymotion 24 Samstag, 30. März 13 -
#inspect Dispatch.once Upon A Time - Executes a block object
once and only once in your app lifetime please don’t use it for UITableView cell layout :-) at least in Rubymotion 24 Samstag, 30. März 13 -
#inspect NSOperationQueue NSOperation NSOperation NSOperation NSOperation N SO perationQ ueue
26 Samstag, 30. März 13 -
#inspect NSOperationQueue queue.addOperationWithBlock(->{ // ... do your long task })
queue = NSOperationQueue.alloc.init queue.name = “com.company.app.task” 27 Samstag, 30. März 13 -
#inspect task = NSBlockOperation.blockOperationWithBlock(->{ // ... do your long task
}) queue.addOperation(task) NSOperationQueue queue = NSOperationQueue.alloc.init queue.name = “com.company.app.task” 27 Samstag, 30. März 13 -
#inspect NSOperationQueue queue = NSOperationQueue.alloc.init queue.name = “com.company.app.task” task1 =
NSInvocationOperation.alloc.initWithTarget(self, selector:‘task1:’, object:”obj”) task2 = NSInvocationOperation.alloc.initWithTarget(self, selector:‘task2’, object:nil) queue.addOperations([task1, task2], waitUntilFinished:false) 27 Samstag, 30. März 13 -
#inspect Embrace Immutability NSString => String # => NSString.stringWithString("") NSArray
=> Array # => NSArray.arrayWithArray([]) 29 Samstag, 30. März 13 -
#inspect Embrace Immutability NSString => String # => NSString.stringWithString("") NSArray
=> Array # => NSArray.arrayWithArray([]) NSDictionary => Hash # => NSDictionary.dictionaryWithDictionary({}) 29 Samstag, 30. März 13 -
#inspect GCD Gotchas Thread safety Variable Scope Queue INCEPTION 30
Samstag, 30. März 13 -
#inspect •Don't be afraid spawn Queues •Update UI only in
the Main Queue •Dispatch::Queue.main is your Friend Working with Graphics It's A trap! 32 Samstag, 30. März 13 -
#inspect GCD NSOperation Work Unit Block NSOperation Can cancel? No
Yes Dependencies? No Yes Concurrent execution? Yes Yes Change Queue? No Yes NSOperationQueue vs GCD 34 Samstag, 30. März 13 -
#inspect much more!!! you can get so much more from
GCD. e.g: you can replace your NSTimer with Dispatch::Source 35 Samstag, 30. März 13 -
#inspect much more!!! Dispatch::Semaphore you can get so much more
from GCD. e.g: you can replace your NSTimer with Dispatch::Source 35 Samstag, 30. März 13 -
#inspect much more!!! Dispatch::Semaphore Dispatch::Source you can get so much
more from GCD. e.g: you can replace your NSTimer with Dispatch::Source 35 Samstag, 30. März 13 -
#inspect def fibonacci2(n) return n if n < 2 fib1
= fibonacci(n-1) fib2 = fibonacci(n-2) fib1 + fib2 end def fibonacci(n) return n if n < 2 fib1 = Dispatch::Promise.new { fibonacci(n-1) } fib2 = Dispatch::Promise.new { fibonacci(n-2) } fib1 + fib2 end n = 100 Benchmark.bm do |x| x.report("Parallel") { n.times do ; fibonacci(10); end } x.report("Sequential") { n.times do ; fibonacci2(10);end } end 37 Samstag, 30. März 13 -
#inspect n 0 5 100 200 300 400 500 Parallel
Sequential 0,000000 0,159890 3,394287 8,568163 15,042915 29,275532 40,513081 0,000000 0,123077 4,513412 18,685437 40,315345 96,669930 174,162173 0 50 100 150 200 0 5 100 200 300 400 500 Naïve Fibonacci sequence Parallel Sequential 37 Samstag, 30. März 13 -
#inspect Things That Can Be Slow • Memory allocation •
View creation • Drawing • Questionable algorithms • Questionable data structures • I/O • Blocking on information • Unnecessary work 40 Samstag, 30. März 13 -
#inspect “We should forget about small efficiencies, say abou...t 97%
of the time: premature optimization is the root of all evil.” Donald Knuth ... 41 Samstag, 30. März 13 -
#inspect Queues Dispatch::Queue.new(“com.company.app.task”) Dispatch::Queue.concurrent(“com.company.app”) Dispatch::Queue.concurrent(priority=:high) Dispatch::Queue.main queue#current queue#label queue#sync queue#async
queue#after queue#apply queue#dispatch_object queue#suspended? queue#suspend! queue#resume! Groups Dispatch::Group.new group#wait group#on_completion [DEPRECATED] group#notify Semaphore Dispatch::Semaphore.new(count=2) semaphore#signal semaphore#wait(time=Dispatch::TIME_NOW) Source Dispatch::Source.new(type, handle, mask, queue) Dispatch::Source.timer(delay, interval, leeway, queue) src#<< source#merge src#data src#mask src#cancel! src#cancelled? Constants Dispatch::TIME_NOW Dispatch::TIME_FOREVER 42 Samstag, 30. März 13