Computer >> Hướng Dẫn Máy Tính >  >> Điện Thoại Thông Minh >> iPhone

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Concurrency trong iOS là chủ đề khổng lồ. Vậy bài này zoom vào sub-topic về queues và Grand Central Dispatch (GCD).

Cụ thể, khám phá khác biệt giữa serial và concurrent queues, cũng như khác biệt giữa synchronous và asynchronous execution.

Nếu chưa bao giờ dùng GCD, bài này là điểm khởi đầu tuyệt vời. Nếu có kinh nghiệm GCD nhưng vẫn tò mò về chủ đề trên, tôi nghĩ bạn vẫn thấy hữu ích. Và hy vọng bạn học thêm một hai điều mới.

Tôi tạo SwiftUI companion app demo trực quan các concept trong bài. App cũng có quiz vui ngắn khuyến khích thử trước và sau đọc bài. Tải source code ở đây, hoặc public beta ở đây.

Sẽ bắt đầu với intro GCD, sau đó giải thích chi tiết sync, async, serial, concurrent. Sau đó cover pitfalls khi làm việc concurrency. Cuối cùng summary và general advice.

Giới Thiệu

Hãy bắt đầu với brief intro GCD và dispatch queues. Tự do skip đến section Sync vs Async nếu đã quen.

Concurrency Và Grand Central Dispatch

Concurrency tận dụng việc device có multiple CPU cores. Để dùng cores này, cần multiple threads. Tuy nhiên threads là low-level tool, quản lý threads thủ công hiệu quả cực khó.

Grand Central Dispatch do Apple tạo hơn 10 năm trước như abstraction giúp developer viết multi-threaded code không cần manually tạo và quản lý threads.

Với GCD, Apple dùng asynchronous design approach cho vấn đề. Thay vì tạo threads trực tiếp, bạn dùng GCD schedule work tasks, và system perform tasks đó bằng cách dùng tốt nhất resources. GCD handle tạo threads cần thiết và schedule tasks trên threads đó, chuyển gánh nặng thread management từ developer sang system.

Lợi thế lớn GCD: không lo hardware resources khi viết concurrent code. GCD manage thread pool cho bạn, scale từ single-core Apple Watch lên many-core MacBook Pro.

Dispatch Queues

Đây là building blocks chính của GCD cho phép execute arbitrary blocks của code dùng set parameters bạn define. Tasks trong dispatch queues luôn start theo first-in, first-out (FIFO). Lưu ý tôi nói started, vì completion time tasks phụ thuộc nhiều yếu tố, không guaranteed FIFO (sẽ nói sau.)

Làm đại, có ba loại queue:

  • Main dispatch queue (serial, pre-defined)
  • Global queues (concurrent, pre-defined)
  • Private queues (serial hoặc concurrent, bạn tạo)

Mọi app có Main queue, là serial queue execute tasks trên main thread. Queue này responsible vẽ UI app và respond user interactions (touch, scroll, pan, v.v.) Nếu block queue này quá lâu, iOS app sẽ như freeze, macOS app show beach ball/spinning wheel.

Khi làm long-running task (network call, computationally intensive work, v.v.), tránh freeze UI bằng cách làm work trên background queue. Sau đó update UI với kết quả trên main queue:

URLSession.shared.dataTask(with: url) { data, response, error in if let data = data { DispatchQueue.main.async { // UI work self.label.text = String(data: data, encoding: .utf8) } } }
URLSession delivers callbacks trên background queue

Rule of thumb: tất cả UI work phải execute trên Main queue. Bật Main Thread Checker trong Xcode nhận warning khi UI work execute trên background thread.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Ngoài main queue, mọi app có sẵn several pre-defined concurrent queues với varying levels Quality of Service (abstract notion of priority trong GCD.)

Ví dụ, code submit work async đến queue user interactive (highest priority) QoS:

DispatchQueue.global(qos: .userInteractive).async { print("We're on a global concurrent queue!") }

Hoặc gọi default priority global queue bằng cách không specify QoS:

DispatchQueue.global().async { print("Generic global queue") }
default QoS rơi giữa user initiated và utility

Thêm, bạn tạo private queues dùng syntax:

let serial = DispatchQueue(label: "com.besher.serial-queue") serial.async { print("Private serial queue") }
private queues mặc định serial

Khi tạo private queues, giúp dùng descriptive label (như reverse DNS notation), hỗ trợ debug trong Xcode navigator, lldb, Instruments:

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes
Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Mặc định private queues serial (sẽ giải thích nghĩa này ngay, promise!) Nếu muốn private concurrent queue, dùng optional attributes parameter:

let concurrent = DispatchQueue(label: "com.besher.serial-queue", attributes: .concurrent) concurrent.sync { print("Private concurrent queue") }

Có optional QoS parameter. Private queues bạn tạo cuối cùng sẽ land vào một trong global concurrent queues dựa trên parameters.

Task Chứa Gì?

Đề cập dispatch tasks đến queues. Tasks là bất kỳ block code nào submit đến queue dùng functions sync hoặc async. Chúng có thể submit dạng anonymous closure:

DispatchQueue.global().async { print("Anonymous closure") }

Hoặc trong dispatch work item perform sau:

let item = DispatchWorkItem(qos: .utility) { print("Work item to be executed later") }
notice how we defined a task QoS here

Bất kể dispatch synchronously hay asynchronously, serial hay concurrent queue, tất cả code trong một task sẽ execute line by line. Concurrency chỉ relevant khi evaluate multiple tasks.

Ví dụ, nếu có 3 loops trong cùng task, loops này luôn execute theo thứ tự:

DispatchQueue.global().async { for i in 0..<10 { print(i) } for _ in 0..<10 { print("?") } for _ in 0..<10 { print("?") } }

Code này luôn in ra mười chữ số 0-9, theo sau mười blue circles, mười broken hearts, bất kể dispatch closure như thế nào.

Individual tasks cũng có own QoS level (mặc định dùng priority của queue.) Sự phân biệt queue QoS và task QoS dẫn đến behavior thú ý sẽ discuss ở section priority inversion.

Bây giờ bạn có thể wonder serial và concurrent là gì. Cũng wonder khác biệt sync và async khi submit tasks. Đưa chúng ta đến trọng tâm bài, hãy dive in!

Sync vs Async

Khi dispatch task đến queue, chọn synchronously hay asynchronously dùng functions sync và async. Sync và async chủ yếu ảnh hưởng source của submitted task, nghĩa là queue nơi nó được submitted từ.

Khi code reaches sync statement, nó block current queue cho đến task complete. Khi task return/complete, control trả về caller, code sau sync task tiếp tục.

Nghĩ sync đồng nghĩa 'blocking'.

async statement, ngược lại, execute asynchronously wrt current queue, và immediately trả control về caller không chờ async closure execute. Không guarantee khi nào code trong async closure sẽ execute.

Current Queue?

Có thể không rõ source, hay current, queue là gì, vì không luôn explicitly defined trong code.

Ví dụ, nếu gọi sync statement trong viewDidLoad, current queue là Main dispatch queue. Nếu gọi cùng function trong URLSession completion handler, current queue là background queue.

Quay lại sync vs async, lấy ví dụ:

DispatchQueue.global().sync { print("Inside") } print("Outside") // Console output: // Inside // Outside

Code trên block current queue, vào closure execute code trên global queue in "Inside", rồi in "Outside". Thứ tự guaranteed.

Thử async:

DispatchQueue.global().async { print("Inside") } print("Outside") // Potential console output (based on QoS): // Outside // Inside

Code bây giờ submit closure đến global queue, rồi ngay lập tức chạy dòng tiếp. Sẽ likely in "Outside" trước "Inside", nhưng order không guaranteed. Phụ thuộc QoS source/destination queues, và factors khác system control.

Threads là implementation detail trong GCD — không direct control, chỉ deal dùng queue abstractions. Tuy nhiên, tôi nghĩ 'peek under the covers' thread behaviour hữu ích hiểu challenges GCD.

Ví dụ, khi submit task dùng sync, GCD optimize performance bằng cách execute task trên current thread (caller.)

Có một exception: khi submit sync task đến main queue — làm vậy luôn run task trên main thread không phải caller. Behaviour này có ramifications sẽ explore ở section priority inversion.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

From Dispatcher on Github

Dùng Cái Nào?

Khi submit work đến queue, Apple recommend async execution hơn sync. Tuy nhiên, có tình huống sync tốt hơn, như dealing with race conditions, hoặc perform very small task. Sẽ cover sau.

Hệ quả lớn của async work trong function: function không còn directly return values (nếu depend trên async work). Phải dùng closure/completion handler parameter deliver results.

Demo concept này, lấy function nhỏ nhận image data, perform expensive computation process image, trả result:

func processImage(data: Data) -> UIImage? { guard let image = UIImage(data: data) else { return nil } // calling an expensive function let processedImage = upscaleAndFilter(image: image) return processedImage }

Trong ví dụ, function upscaleAndFilter(image:) có thể mất vài giây, muốn offload vào separate queue tránh freeze UI. Tạo dedicated queue image processing, dispatch expensive function async:

let imageProcessingQueue = DispatchQueue(label: "com.besher.image-processing") func processImageAsync(data: Data) -> UIImage? { guard let image = UIImage(data: data) else { return nil } imageProcessingQueue.async { let processedImage = upscaleAndFilter(image: image) return processedImage } }
code này không compile!

Hai issue với code này. Thứ nhất, return statement trong async closure, không còn return value cho function processImageAsync(data:), hiện không serve purpose.

Nhưng issue lớn hơn: function processImageAsync(data:) không còn return value, vì function reach end body trước khi vào async closure.

Fix error, adjust function không còn directly return value. Thay vào đó, có completion handler parameter mới gọi khi async function complete work:

let imageProcessingQueue = DispatchQueue(label: "com.besher.image-processing") func processImageAsync(data: Data, completion: @escaping (UIImage?) -> Void) { guard let image = UIImage(data: data) else { completion(nil) return } imageProcessingQueue.async { let processedImage = self.upscaleAndFilter(image: image) completion(processedImage) } }

Như ví dụ, thay đổi làm function async propagated đến caller, giờ phải pass closure và handle results async. Bằng introduce async task, potentially modify chain của several functions.

Concurrency và async execution thêm complexity project như quan sát. Indirection cũng làm debug khó hơn. Đó là lý do really pays off think about concurrency early in design — không phải tack on ở cuối design cycle.

Sync execution, ngược lại, không tăng complexity. Thay vào đó, cho phép continue dùng return statements như trước. Function chứa sync task không return cho đến code trong task complete. Vì vậy không cần completion handler.

Nếu submit tiny task (ví dụ update value), consider sync. Không chỉ giữ code simple, cũng perform tốt hơn — Async believed incur overhead outweigh benefit làm async cho tiny tasks under 1ms.

Nếu submit large task, như image processing, consider async tránh block caller quá lâu.

Dispatching Trên Cùng Queue

An toàn dispatch task async từ queue vào chính nó (ví dụ dùng .asyncAfter trên current queue), nhưng KHÔNG THỂ dispatch task synchronously từ queue vào cùng queue. Làm vậy sẽ deadlock crash app ngay!

Issue này manifest khi perform chain synchronous calls lead back original queue. Nghĩa là bạn sync taskonto another queue, và khi task complete, nó sync results back vào original queue, leading to deadlock. Dùng async tránh crash.

Blocking Main Queue

Dispatch tasks synchronously từ main queue sẽ block queue đó, freeze UI, cho đến task complete. Vậy better avoid dispatch work synchronously từ main queue trừ khi perform really light work.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

prefer to use async from the main queue

Serial vs Concurrent

Serial và concurrent ảnh hưởng destination — queue work đã submitted to run. Ngược lại sync và async ảnh hưởng source.

Serial queue không execute work trên hơn một thread tại một thời điểm, bất kể dispatch bao nhiêu tasks trên queue. Kết quả, tasks guaranteed không chỉ start, mà terminate, theo FIFO order.

Hơn nữa, khi block serial queue (dùng sync call, semaphore, hoặc tool khác), all work trên queue halt cho đến block over.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

From Dispatcher on Github

Concurrent queue có thể spawn multiple threads, system quyết định bao nhiêu threads tạo. Tasks luôn start FIFO, nhưng queue không chờ tasks finish trước khi start next task, do đó tasks trên concurrent queues có thể finish bất kỳ order nào.

Khi perform blocking command trên concurrent queue, nó không block other threads trên queue này. Thêm, khi concurrent queue bị block, nó risk thread explosion. Sẽ cover chi tiết sau.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

From Dispatcher on Github

Main queue app là serial. Tất cả global pre-defined queues concurrent. Private dispatch queue bạn tạo mặc định serial, nhưng set concurrent dùng optional attribute như thảo luận trước.

Quan trọng note: concept serial vs concurrent chỉ relevant khi discuss specific queue. Tất cả queues concurrent relative to each other.

Nghĩa là, nếu dispatch work async từ main queue đến private serial queue, work đó complete concurrently wrt main queue. Và nếu tạo hai serial queues khác nhau, perform blocking work trên một, queue kia unaffected.

Demo concurrency của multiple serial queues, lấy ví dụ:

let serial1 = DispatchQueue(label: "com.besher.serial1") let serial2 = DispatchQueue(label: "com.besher.serial2") serial1.async { for _ in 0..<5 { print("?") } } serial2.async { for _ in 0..<5 { print("?") } }

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Cả hai queue serial, nhưng results jumbled vì execute concurrently relative to each other. Fakt chúng serial (hoặc concurrent) no effect trên result. QoS level quyết định ai thường finish first (order không guaranteed).

Nếu muốn đảm bảo loop đầu finish first trước khi start loop thứ hai, submit first task synchronously từ caller:

let serial1 = DispatchQueue(label: "com.besher.serial1") let serial2 = DispatchQueue(label: "com.besher.serial2") serial1.sync { // <---- we changed this to 'sync' for _ in 0..<5 { print("?") } } // we don't get here until first loop terminates serial2.async { for _ in 0..<5 { print("?") } }

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Không nhất thiết desirable, vì bây giờ block caller while first loop executing.

Để avoid block caller, submit both tasks async, nhưng đến same serial queue:

let serial = DispatchQueue(label: "com.besher.serial") serial.async { for _ in 0..<5 { print("?") } } serial.async { for _ in 0..<5 { print("?") } } 

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Bây giờ tasks execute concurrently wrt caller, cũng giữ order intact.

Nếu make single queue concurrent via optional parameter, quay lại jumbled results, như expected:

let concurrent = DispatchQueue(label: "com.besher.concurrent", attributes: .concurrent) concurrent.async { for _ in 0..<5 { print("?") } } concurrent.async { for _ in 0..<5 { print("?") } }

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Đôi khi confuse synchronous execution với serial execution (ít nhất tôi), nhưng chúng rất khác. Thử đổi first dispatch line 3 từ ví dụ trước sang sync call:

let concurrent = DispatchQueue(label: "com.besher.concurrent", attributes: .concurrent) concurrent.sync { for _ in 0..<5 { print("?") } } concurrent.async { for _ in 0..<5 { print("?") } }
this can be misleading

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Đột nhiên, results quay lại perfect order. Nhưng đây concurrent queue, how could that happen? sync statement somehow turn thành serial queue?

Câu trả lời KHÔNG!

Hơi tricky. Điều xảy ra: không reach async call cho đến first task completed execution. Queue vẫn concurrent, nhưng trong zoomed-in section code này. nó appear như serial. Vì block caller, không proceed next task cho đến first finished.

Nếu queue khác ở đâu đó trong app submit work đến queue này while vẫn executing sync statement, work đó sẽ run concurrently với gì đang chạy ở đây, vì nó vẫn concurrent queue.

Dùng Cái Nào?

Serial queues tận dụng CPU optimizations và caching, giúp reduce context switching.

Apple recommend start với one serial queue per subsystem app — ví dụ one cho networking, one cho file compression, v.v. Nếu need arises, expand sau sang hierarchy queues per subsystem dùng setTarget method hoặc optional target parameter khi build queues.

Nếu run into performance bottleneck, measure app performance xem concurrent queue giúp. Nếu không thấy measurable benefit, better stick to serial queues.

Pitfalls (Cạm Bẫy)

Priority Inversion Và Quality of Service

Priority inversion là khi high priority task bị prevented chạy bởi lower priority task, effectively inverting relative priorities.

Situation này thường xảy ra khi high QoS queue share resource với low QoS queue, và low QoS queue get lock trên resource đó.

Nhưng tôi muốn cover scenario khác relevant hơn discussion — khi submit tasks đến low QoS serial queue, rồi submit high QoS task đến cùng queue. Scenario này cũng priority inversion, vì high QoS task phải wait lower QoS tasks finish.

GCD resolve priority inversion bằng temporarily raise QoS của queue chứa low priority tasks 'ahead of', hoặc blocking, high priority task.

Giống như có xe kẹt trước xe cứu thương. Đột nhiên cho cross red light để cứu thương move (thực tế xe move sang bên, nhưng hãy imagine narrow (serial) street, you get the point :-P)

Illustrate inversion problem, bắt đầu code:

 enum Color: String { case blue = "?" case white = "⚪️" } func output(color: Color, times: Int) { for _ in 1...times { print(color.rawValue) } } let starterQueue = DispatchQueue(label: "com.besher.starter", qos: .userInteractive) let utilityQueue = DispatchQueue(label: "com.besher.utility", qos: .utility) let backgroundQueue = DispatchQueue(label: "com.besher.background", qos: .background) let count = 10 starterQueue.async { backgroundQueue.async { output(color: .white, times: count) } backgroundQueue.async { output(color: .white, times: count) } utilityQueue.async { output(color: .blue, times: count) } utilityQueue.async { output(color: .blue, times: count) } // next statement goes here }

Tạo starter queue (submit tasks từ), cũng như hai queues khác QoS. Rồi dispatch tasks đến mỗi queue, mỗi task in equal số circles màu cụ thể (utility queue blue, background white.)

Vì tasks submit async, mỗi lần run app, thấy kết quả khác nhau. Tuy nhiên, như expected, queue lower QoS (background) hầu như luôn finish last. Thực tế, 10-15 circles cuối thường all white.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

no surprises here

Nhìn gì xảy ra khi submit sync task đến background queue sau last async statement. Không cần print trong sync statement, chỉ thêm dòng này đủ:

// add this after the last async statement, // still inside starterQueue.async backgroundQueue.sync {}

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

priority inversion

Kết quả console flipped! Bây giờ, higher priority queue (utility) luôn finish last, và 10-15 circles cuối blue.

Hiểu tại sao, revisit fact synchronous work executed trên caller thread (trừ submit đến main queue.)

Trong ví dụ, caller (starterQueue) có top QoS (userInteractive.) Vậy sync task seemingly innocuous không chỉ block starter queue, mà cũng run trên high QoS thread của starter. Task run với high QoS, nhưng có hai task khác ahead trên cùng background queue có background QoS. Priority inversion detected!

Như expected, GCD resolve inversion bằng raise QoS entire queue tạm match high QoS task. Kết quả, all tasks trên background queue run ở user interactive QoS, higher than utility QoS. Đó là lý do utility tasks finish last!

Side-note: Nếu remove starter queue từ ví dụ và submit từ main queue thay thế, similar results, vì main queue cũng user interactive QoS.

Để avoid priority inversion, cần avoid block starter queue với sync statement. Dùng async solve problem.

Mặc dù không luôn ideal, minimize priority inversions bằng stick to default QoS khi tạo private queues hoặc dispatch đến global concurrent queue.

Thread Explosion (Bùng Nổ Thread)

Khi dùng concurrent queue, risk thread explosion nếu không careful. Happen khi submit tasks đến concurrent queue đang blocked (ví dụ semaphore, sync, hoặc cách khác.) Tasks sẽ run, nhưng system likely spin up new threads accommodate new tasks, và threads không rẻ.

Đây có thể lý do Apple suggest start với serial queue per subsystem app, vì mỗi serial queue chỉ dùng one thread. Nhớ serial queues concurrent relative to other queues, nên vẫn get performance benefit offload work đến queue, даже если not concurrent.

Race Conditions (Điều Kiện Đua)

Swift Arrays, Dictionaries, Structs, và value types khác không thread-safe mặc định. Ví dụ, multiple threads try access và modify same array, sẽ run into trouble.

Có different solutions readers-writers problem, như locks hoặc semaphores. Nhưng relevant solution tôi muốn discuss là dùng isolation queue.

Giả sử có array integers, muốn submit async work reference array. Miễn work chỉ reads array không modify, safe. Nhưng ngay khi try modify array trong async task, introduce instability.

Tricky problem vì app run 10 times no issues, crash lần 11. Tool handy: Thread Sanitizer Xcode. Enable option giúp identify potential race conditions.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

this option is only available on the simulator

Demo problem, lấy ví dụ (contrived):

class ViewController: UIViewController { let concurrent = DispatchQueue(label: "com.besher.concurrent", attributes: .concurrent) var array = [1,2,3,4,5] override func viewDidLoad() { for _ in 0...1 { race() } } func race() { concurrent.async { for i in self.array { // read access print(i) } } concurrent.async { for i in 0..<10 { self.array.append(i) // write access } } } }

Một async task modify array bằng append. Thử run simulator, có thể không crash. Run đủ lần (hoặc tăng loop frequency line 7), eventually crash. Enable thread sanitizer, warning mỗi lần run.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Deal race condition, thêm isolation queue dùng barrier flag. Flag cho outstanding tasks trên queue finish, nhưng block further tasks execute cho đến barrier task complete.

Nghĩ barrier như janitor dọn public restroom (shared resource). Có multiple (concurrent) stalls người dùng.

Khi đến, janitor đặt biển báo cleaning (barrier) block newcomers enter cho đến cleaning done, nhưng janitor không start cleaning cho đến tất cả người bên trong finish. Khi all leave, janitor clean restroom in isolation.

Khi done, janitor gỡ sign (barrier) để người queue outside enter.

Code trông như sau:

class ViewController: UIViewController { let concurrent = DispatchQueue(label: "com.besher.concurrent", attributes: .concurrent) let isolation = DispatchQueue(label: "com.besher.isolation", attributes: .concurrent) private var _array = [1,2,3,4,5] var threadSafeArray: [Int] { get { return isolation.sync { _array } } set { isolation.async(flags: .barrier) { self._array = newValue } } } override func viewDidLoad() { for _ in 0...15 { race() } } func race() { concurrent.async { for i in self.threadSafeArray { print(i) } } concurrent.async { for i in 0..<10 { self.threadSafeArray.append(i) } } } }

Thêm isolation queue mới, restrict access private array dùng getter setter place barrier khi modify array.

Getter cần sync để directly return value. Setter có thể async, vì không cần block caller while write happening.

Có thể dùng serial queue không barrier solve race condition, nhưng mất advantage concurrent read access array. Có thể hợp lý case của bạn, bạn decide.

Kết Luận

Cảm ơn đã đọc đến đây! Hy vọng bạn học được điều mới. Tóm tắt và general advice:

Tóm Tắt

  • Queues luôn start tasks FIFO order
  • Queues luôn concurrent relative to other queues
  • Sync vs Async concerns the source
  • Serial vs Concurrent concerns the destination
  • Sync đồng nghĩa 'blocking'
  • Async immediately return control to caller
  • Serial dùng single thread, guarantee execution order
  • Concurrent dùng multiple-threads, risk thread explosion
  • Think about concurrency early in design cycle
  • Synchronous code dễ reason about và debug
  • Avoid relying on global concurrent queues nếu possible
  • Consider start với serial queue per subsystem
  • Switch to concurrent queue chỉ nếu thấy measurable performance benefit

Thích metaphor từ Swift Concurrency Manifesto 'island of serialization in a sea of concurrency'. Sentiment cũng shared trong tweet Matt Diephouse:

Khi apply concurrency với philosophy đó, tôi nghĩ giúp achieve concurrent code reasoned about không bị lost in mess of callbacks.

Nếu có câu hỏi hoặc comment, tự do reach out tôi trên Twitter

Besher Al Maleh

Cover photo by Onur K on Unsplash

Tải companion app ở đây:

almaleh/DispatcherCompanion app to my article on concurrency. Contribute to almaleh/Dispatcher development by creating an account on GitHub.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesalmalehGitHubLàm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Xem thêm bài khác của tôi:

Fireworks — Visual particles editor cho SwiftGenerate Swift code on the fly cho macOS và iOS khi design và iterate particle effects

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesBesher Al MalehFlawless iOS

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesYou don't (always) need [weak self]Trong bài này, nói về weak self trong Swift closures tránh retain cycles & explore cases có thể hoặc không cần capture self weakly.

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesBesher Al MalehFlawless iOS

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

Further reading:

IntroductionExplains how to implement concurrent code paths in an application.Concurrent Programming: APIs and Challenges · objc.ioobjc.io publishes books on advanced techniques and practices for iOS and OS X development

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesFlorian Kugler

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesLow-Level Concurrency APIs · objc.ioobjc.io publishes books on advanced techniques and practices for iOS and OS X development

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesDaniel Eggert

https://khanlou.com/2016/04/the-GCD-handbook/

Concurrent vs serial queues in GCDI'm struggling to fully understand the concurrent and serial queues in GCD. I have some issues and hoping someone can answer me clearly and at the point.I'm reading that serial queues are created...

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesBogdan AlexandruStack Overflow

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes

WWDC Videos:

Modernizing Grand Central Dispatch Usage - WWDC 2017 - Videos - Apple DevelopermacOS 10.13 and iOS 11 have reinvented how Grand Central Dispatch and the Darwin kernel collaborate, enabling your applications to run...

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesApple Developer

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesBuilding Responsive and Efficient Apps with GCD - WWDC 2015 - Videos - Apple DeveloperwatchOS and iOS Multitasking place increased demands on your application's efficiency and responsiveness. With expert guidance from the...

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution ModesApple Developer

Làm Chủ Concurrency iOS: Hiểu GCD Queues & Execution Modes