Date post: | 05-Dec-2014 |
Category: |
Technology |
Upload: | kuba-brecka |
View: | 3,056 times |
Download: | 1 times |
Grand Central Dispatch and multi-threading
Kuba Brecka @kubabrecka
Terminology
• Parallel
• Multi-threaded
• Concurrent
• Simultaneous
• Asynchronous
Why parallelize?• Responsiveness
• “when I scroll, it’s smooth”
• Performance
• “it works fast”
• Energy saving
• “it doesn’t drain my battery”
• Convenience
• some things are parallel by nature, e.g. running two completely separate apps
How?• Multiple processes
• XPC, fork
• Multiple threads
• POSIX Threads, NSThread
• High-level thread abstraction
• Operation queues, dispatch queues
• GPGPU
• Instruction-level parallelism
• superscalar CPUs, pipelining, vector instructions
• Multiple PCs
• servers, clouds
Threads• What is a thread?
• It’s an abstraction made by the OS
• The CPU has no such concept
• Represents a line of calculation
• Has an ID, a stack, thread-local storage, priority, CPU registers
• Shares memory and resources within a process
• The OS scheduler runs/pauses threads
• context switching
Issues with threading• Race conditions
• the result depends on the timing of the scheduler
• the behavior is non-deterministic
• can result in almost anything
• crash, wrong result, corrupted data
• So, you have to use locks/mutexes/…
• More issues: deadlocks, livelocks, starvation
• Even the best guys have trouble with these
• Security consequences, vulnerabilities
Know your enemy
• The compiler
• The CPU
• The memory
• Time
• Your brain
The iPhone has matured
iPhone 4 512 MB RAM
A4 SoC (1 core) 800 MHz
iPhone 4S 512 MB RAM
A5 SoC (2 core) 800 MHz
iPhone 5 1 GB RAM
A6 SoC (2 core) 1300 MHz
iPhone 5S 1 GB RAM
A7 SoC (2 core) 1300 MHz
ARM has matured• Apple A5 (2011)
• ARM Cortex-A9 MPCore
• 2 cores
• out-of-order execution
• speculative execution
• superscalar, pipelining (8 stages)
• NEON 128-bit SIMD
• Apple A7 (2013)
• ARMv8-A “Cyclone”
• 64-bit, 32 registers, per-core L1 cache
iOS has matured• The kernel knows a lot more about the system than
the developer
• GCD
• Operation Queues
• LLVM, compiler optimizations
• GPU computations
• Accelerate.framework
iOS threading technologies• Multiple processes – forking disabled, no XPC
• Low-level threads
• POSIX Threads (pthread)
• NSThread
• -[NSObject performSelectorInBackground:withObject:]
• Higher-level abstractions
• NSOperationQueue, NSOperation
• GCD
Parallelizing tasks vs. algorithms
• Task = a standalone unit of work
• has some inputs, gives some outputs
• “add a blur effect to these 1000 photos”
• 1 photo = 1 task (independent)
• “add a blur effect to this one 5000x5000px photo”
• 1 task = ?
• Some algorithms simply cannot be parallelized (you will not get any significant speedup)
What’s thread safety?• “Thread-safe object”
• you can safely use the object from multiple threads at the same time
• the internal state of the object will not get corrupted and it will behave correctly
• When you don’t know if an object is thread-safe, you have to assume it isn’t
• How do you make your object thread-safe?
• immutability, locks, atomic reads/writes
Shared mutable state• Exclusive immutable object = no problem
• Shared immutable object = no problem
• Exclusive mutable object = no problem
• Shared mutable object
• root of all evil
• you always want to minimize this
Global variables• “Global variables are bad”
• Multi-threading is another very good reason not to use global variables / global state
• Global variables are always shared
• Watch out for “hidden” global state:
• working directory, chdir()
• environment variables, putenv()
Thread-safety vs. iOS• Terrible lack of proper documentation
• Most of the low-level Obj-C runtime is thread-safe
• memory management, ARC, weak references, …
• Immutable objects (NSString, NSArray, …) are thread-safe
• A few other classes are thread-safe
• Usually it’s thread-safe to call class methods
• google for “iOS thread safety”
• https://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html
Grand Central Dispatch• Let’s not think about threads
• Instead, let’s think about tasks
• New concepts:
• Tasks
• Queues
• Queue-specific data
• Dispatch groups
• Dispatch sources
• Synchronization
• Semaphores, barriers
• C API (!) but has ARC and works with blocks
GCD queues• Main queue
• there is just one, executed on the main thread
• Concurrent queue
• tasks run concurrently
• 4 pre-made concurrent queues with different priorities
• DISPATCH_QUEUE_PRIORITY_DEFAULT, _HIGH, _LOW, _BACKGROUND
• you can make your own
• Serial queue
• only one task at a time, in order
• you can make your own
GCD task API• Get/create a queue:
• dispatch_get_global_queue
• dispatch_get_main_queue
• dispatch_queue_create
• Submit task:
• dispatch_sync
• dispatch_async
• dispatch_apply
GCD convenience API
• dispatch_once
• guarantees the code run only run once
• use to implement a proper and fast singleton
• dispatch_after
• execute the task at a specific time
It’s not threads• GCD uses threads, but the threads are completely
managed by GCD
• You can’t assume your code will run on any specific thread
• even two tasks from the same serial queue can run on different threads
• Don’t use thread-local storage
• Don’t use thread priorities
Demo
Solutions• Avoid shared mutable state
• communicate by message passing
• design your objects as immutable
• avoid multithreading
• Synchronization
• You must always have “a plan”
• if you can’t tell which code is supposed to run in which thread/queue, then nobody can help you
• if you can’t tell which data can be accessed from which thread/queue, then nobody can help you
• Thank you. Kuba Brecka
@kubabrecka iosak.cz