Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Let'swift "Concurrency in swift"

192 views

Published on

Speech in Let'Swift conference on 23, Sep 2017.
This is about various concurrency APIs in swift and async/await, actor model and debugging option.

2017년 9월 23일에 Let'Swift에서 발표한 스위프트에서 동시성에 대한 자료입니다.
현재 사용할 수 있는 다양한 API에 대해 정리해보고 앞으로 나아갈길 그리고 디버깅에 대한 이야기를 했습니다.

Published in: Mobile
  • Be the first to comment

  • Be the first to like this

Let'swift "Concurrency in swift"

  1. 1. letswift(17) Concurrency 
 in Swift OSXDEV.org허 혁
  2. 2. Concurrency 
 in Swift LINE+
 Hyuk Hur
  3. 3. Who?
  4. 4. Concurrency 
 in Swift LINE+
 Hyuk Hur
  5. 5. Concurrency 
 in iOS LINE+
 Hyuk Hur
  6. 6. Concurrency 
 in Foundation LINE+
 Hyuk Hur
  7. 7. Parallelism VS Concurrency Parallelism
 
 
 
 
 
 
 
 Concurrency
 
 
 
 
 
 
 
 TASK 1 SUBTASK 1 SUBTASK 2 SUBTASK 3 TASK 1 TASK 2 TASK 3 TASK 1 TASK 2 TASK 3 Critical Section
  8. 8. Concurrency Concurrency
 
 
 
 
 
 
 
 TASK 1 TASK 2 TASK 3 TASK 1 TASK 2 TASK 3 Critical Section
  9. 9. Concurrency Concurrency
 
 
 
 
 
 
 
 TASK 1 TASK 2 TASK 3 TASK 1 TASK 2 TASK 3 Critical Section
  10. 10. Concurrency Concurrency
 
 
 
 
 
 
 
 TASK 1 TASK 2 TASK 3 TASK 1 TASK 2 TASK 3 Critical Section Share Data Share Data Share Data
  11. 11. At the programming language level Channel Coroutine Futures and promises …
  12. 12. At the operating system level Process Thread …
  13. 13. Thread Critical Section Share Data Synchronization …
  14. 14. Synchronization Race conditions Dead lock Starvations IO waiting Rendezvous problem …
  15. 15. At the iOS level Process - Sandbox POSIX Thread - pthread …
  16. 16. At the Foundation framework level RunLoop Timer Thread Operation GDC Process; XPC Task Locking; NSLock NSRecursiveLock NSDistributedLock NSConditionLock NSCondition
  17. 17. At the Foundation framework level NSLock NSRecursiveLock - for recursive function NSDistributedLock - non-blocking lock, for process NSConditionLock - producer-consumer problem NSCondition - POSIX conditions
  18. 18. Darwin objc/objc-sync.h https:// opensource.apple.com/ source/objc4/objc4-709.1/ runtime/objc- sync.mm.auto.html
 
 objc_sync_enter objc_sync_exit objc_sync_wait objc_sync_notify objc_sync_notifyAll
  19. 19. libkern libkern/OSAtomic.h https:// opensource.apple.com/ source/xnu/xnu-3789.70.16/ libkern/libkern/ OSAtomic.h.auto.html deprecated Integer operations Fundamental operations Spinlocks - OSSpinLock Queues - OSQueue Memory barriers
  20. 20. stdatomic.h Darwin.C.stdatomic https://clang.llvm.org/ doxygen/ stdatomic_8h_source.html C11 standard a lock-free data structure
 Integer operations Fundamental operations Spinlocks Queues Memory barriers
  21. 21. Foundation NSThread -> Thread NSTimer NSOperation -> Operation Grand Central Dispatch ( GCD ) NSLock
  22. 22. (NS)Thread class JobThread: Thread { override func main() { doJab() } } // let thread = Thread { doJob() } thread.start() // Thread(target: self, selector: doJab, object: nil)
  23. 23. (NS)Thread Familiarity. Task on exact OS Thread Thread Local Storage [NSThread isMainThread] Timer
  24. 24. (NS)Operation OperationQueue Operation - NSOperation, NSBlockOperation, NSInvocationOperation Operation Dependencies KVO Thread-safe itself isCancelled
  25. 25. (NS)Operation class MyOperation
 init() {
 executing = NO;
 finished = NO;
 } func start() {
 if self.isCancelled {
 willChangeValue(forKey:“isFinished”)
 finished = true
 didChangeValue(forKey:“isFinished”)
 return
 }
 willChangeValue(forKey:“isExecuting”)
 doJob()
 executing = true
 didChangeValue(forKey:“isExecuting”)
 }
  26. 26. (NS)OperationQueue let queue = NSOperationQueue() queue.addOperation(MyOperation()) queue.addOperation(NSBlockOperation(){
 self.doJob()
 })
  27. 27. Grand Central Dispatch ( GCD ) Synchronous and Asynchronous Execution Serial and Concurrent Queues System-Provided Queues WorkItem Priority Dispatch Group Dispatch Semaphore Dispatch Data Dispatch Time (once or after) Dispatch Sources Dispatch I/O Dispatch Object - base object
  28. 28. Grand Central Dispatch ( GCD ) let job: DispatchWorkItem = DispatchWorkItem { print("hello") } let queue: DispatchQueue = DispatchQueue(label: "queue", qos: DispatchQoS.background) let nextTime: DispatchTime = DispatchTime.now() queue.asyncAfter(deadline: nextTime, execute: job)
  29. 29. Make it Thread- safe
  30. 30. At the Objective-C language @synchronized Directive Property atomic Directive
  31. 31. At the swift language @synchronized Directive func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T { objc_sync_enter(lock) defer { objc_sync_exit(lock) } return try body() } //// synchronized(self) { }
  32. 32. At the swift language Property atomic Directive - Imitating Atomic Properties OSAtomic dispatch queue Operation …
  33. 33. Imitating Atomic Properties private var value : Int = 0
 var myProperty: Bool {
 get {
 return value
 }
 set {
 return newValue ? OSAtomicTestAndSet(0, &value) : OSAtomicTestAndClear(0, &value)
 }
 }
  34. 34. Imitating Atomic Properties private let queue = DispatchQueue(label: “atomic_queue”)
 private var _myPropertyStorage: SomeType
 var myProperty: SomeType {
 get {
 var result: SomeType?
 queue.sync {
 result = _myPropertyStorage
 }
 return result!
 }
 
 
 
 set {
 queue.sync {
 _myPropertyStorage = newValue
 }
 }
 }
 }
  35. 35. Choosing dispath queue - heavy but work well. (NS)OperationQueue - OOP, Property, KVO (NS)Lock - faster then GCD, explicit lock and unlock calls OSAtomic - deprecated, lock-free stdatomic - lower overhead, lock-free pthread - straightforward and fast
  36. 36. Concurrency 
 in Swift 5
  37. 37. At the swift language level traditional control flow if switch for while, value type, class reference asynchronous control flow closure, delegate, events
 message passing and data isolation Message Box distributed data and compute interprocess communication: sockets, signals, pipes, MIG, XPC, and many others
  38. 38. At the swift language level traditional control flow Lock, GCD, Thread asynchronous control flow async/await
 
 message passing and data isolation first-class Actor Model distributed data and compute Distributed Actor
  39. 39. At the swift language level traditional control flow Lock, GCD, Thread asynchronous control flow async/await
 
 message passing and data isolation first-class Actor Model distributed data and compute Distributed Actor
  40. 40. async/await C# For asynchronous APIs. a pyramid of doom make error handling awkward make control flow
  41. 41. a pyramid of doom func processImageData1(completionBlock: (result: Image) -> Void) {
 loadWebResource("dataprofile.txt") { dataResource in
 loadWebResource("imagedata.dat") { imageResource in
 decodeImage(dataResource, imageResource) { imageTmp in
 dewarpAndCleanupImage(imageTmp) { imageResult in
 completionBlock(imageResult)
 }
 }
 }
 }
 }
  42. 42. async/await func processImageData1() async -> Image {
 let dataResource = await loadWebResource("dataprofile.txt")
 let imageResource = await loadWebResource("imagedata.dat")
 let imageTmp = await decodeImage(dataResource, imageResource)
 let imageResult = await dewarpAndCleanupImage(imageTmp)
 return imageResult
 }
  43. 43. Actor Model In response to a message that it receives, an actor can: make local decisions, create more actors, send more messages, and determine how to respond to the next message received. Actors may modify private state, but can only affect each other through messages (avoiding the need for any locks).
  44. 44. Actor Model 행위자가 받는 메시지에 대응하여, 행위자는 자체적인 결정을 하고 더 많은 행위자를 만들며, 더 많은 메시지를 보내고, 다음에 받을 메시지에 대한 응답 행위를 결정할 수 있다. 행위자는 개인 상태를 수정할 수 있지만, 메시지를 통해서만 서로에게 영향을 줄 수 있다. (락의 필요성을 제거함)
  45. 45. Actor Model 스스로 행동을 결정 다른 액터 만들기 다른 액터에게 메시지 보내기 다음 메시지를 받으면 어떻게 할지 내 정보 변경 메시지로 다른 액터 정보 변경 요청
  46. 46. Actor Model Actor
  47. 47. Actor Model Actor Actor
  48. 48. Actor Model Actor Actor ActorActor Actor
  49. 49. Actor Model Actor Actor ActorActor Actor
  50. 50. Actor Model Actor Actor ActorActor Actor Mail Box
  51. 51. Actor Model Actor Actor ActorActor Actor Mail Box
  52. 52. Actor Model Actor Actor ActorActor Actor Mail Box MessagesMessages
  53. 53. Actor Model Actor Actor ActorActor Actor Mail Box MessagesMessages Messages Messages Messages
  54. 54. Actor Model Actor Actor ActorActor Actor Mail Box Mail Box Mail Box Mail Box Mail Box
  55. 55. Actor Model Actor Actor ActorActor Actor Mail Box Mail Box Mail Box Mail Box Mail Box
  56. 56. Actor actor TableModel {
 let mainActor : TheMainActor
 var theList : [String] = [] { didSet {
 mainActor.updateTableView(theList)
 }} 
 init(mainActor: TheMainActor) { self.mainActor = mainActor }
 func prettify(_ x : String) -> String { }
 actor func add(entry: String) {
 theList.append(prettify(entry))
 }
 }
  57. 57. Concurrency 
 in Debugging
  58. 58. Thread Sanitizer Data races occur when multiple threads access the same memory without synchronization and at least one access is a write. detects data races at runtime uninitialized mutexes thread leaks
  59. 59. TSan Record timestamp about every memory access. Overhead - CPU 2x~20x slow, Memory 5x~10x
  60. 60. Data Races var message: String? = nil
 var messageIsAvailable: Bool = false
 // Executed on Thread #1
 func producer() {
 message = "hello!"
 messageIsAvailable = true
 }
 // Executed on Thread #2
 func consumer() {
 repeat {
 usleep(1000)
 } while !messageIsAvailable
 print(message)
 }
  61. 61. Swift Access Races Access Race with Mutating Struct Methods
 var messages: [String] = []
 // Executed on Thread #1
 func producer() {
 messages.append("A message");
 }
 // Executed on Thread #2
 func consumer() {
 repeat {
 let message = messages.remove(at: 0)
 print("(message)")
 } while !messages.isEmpty
 }
  62. 62. Swift Access Races Access Race with inout Parameters
 var log: String = ""
 // Executed on Thread #1
 func writeNumbers() {
 print(1, 2, 3, separator: ",", to: &log)
 }
 // Executed on Thread #2
 func writeLetters() {
 print("a", "b", "c", separator:",", to: &log)
 }
  63. 63. Races on Collections Collection Race with a Mutable Array
 let array: NSMutableArray = []
 var sum: Int = 0
 // Executed on Thread #1
 for value in array {
 sum += value as! Int
 }
 // Executed on Thread #2
 array.add(42)
  64. 64. Races on Collections Collection Race with a Mutable Dictionary
 let dictionary: NSMutableDictionary = [:]
 var sum: Int = 0
 // Executed on Thread #1
 for key in dictionary.keyEnumerator() {
 sum += dictionary[key] as! Int
 }
 // Executed on Thread #2
 dictionary["forty-two"] = 42
  65. 65. Uninitialized Mutexes Use of Uninitialized Mutex in C
 static pthread_mutex_t mutex;
 void performWork() {
 pthread_mutex_lock(&mutex); // Error: uninitialized mutex
 // ...
 pthread_mutex_unlock(&mutex);
 }
  66. 66. Uninitialized Mutexes static pthread_once_t once = PTHREAD_ONCE_INIT;
 static pthread_mutex_t mutex;
 void init() { pthread_mutex_init(&mutex, NULL); }
 void performWork() {
 pthread_once(&once, init); // Correct
 pthread_mutex_lock(&mutex);
 // ...
 pthread_mutex_unlock(&mutex);
 }
  67. 67. Thread Leaks Leaked Thread in C
 void *run(){
 pthread_exit(0);
 }
 pthread_t thread;
 pthread_create(&thread, NULL, run, NULL); // Error: thread leak
 sleep(1);
  68. 68. Thread Leaks void *run(){
 pthread_exit(0);
 }
 pthread_t thread;
 pthread_create(&thread, NULL, run, NULL);
 sleep(1);
 pthread_join(thread, NULL); // Correct
  69. 69. Concurrency 
 in Swift
  70. 70. Recap Thread, Operation, GCD async/await, Actor TSan
  71. 71. Thanks

×