Xem chi tiết http://quantrimang.com/clear.ashx?u=/cach-ghep-2-video-chay-song-song-bang-capcut-185599#capcut
Review VNPT SmartBox PC | CPU Intel chạy song song Windows và Android [Hieuhien.vn]Đăng ký dùng miễn phí: https://shorten.asia/x9UmMtu7Xem giá sản phẩm
There are a total of 5 songs in Pushpa The Rise Part - 01. The songs were composed by Devi Sri Prasad, a talented musician. Listen to all of Pushpa The Rise Part - 01 online on JioSaavn.. Find Pushpa new songs and download Pushpa best mp3 songs and music album online. Hindi songs on Raaga.com - A World Of Music. I'm listening to the best music
Điều này đồng nghĩa với việc bạn sẽ phải jailbreak để chạy 2 ứng dụng trên iPhone iOS 14. Sau đây là cách thực hiện chi tiết: B1: Trên iPhone iOS 14 đã jailbreak, bạn mở ứng dụng Cydia và chọn vào “Các nguồn”. B2: Chọn “Sửa” và tiếp tục chọn “thêm” sau đó bạn
mình dùng 2cảm biến siêu âm hoạt động độc lập nhau. 1 timer đếm cho 1 cảm biến, mà 2 cảm biến chạy độc lập với nhau nên mình muốn cho 2 timer chạy song song với nhau thì dùng cách nào. dùng ngắt được không, mình biết dùng cấu trúc thread thì cũng được nhưng k biết cú pháp câu lệnh @@
US$400 – 64GB internal storage, carrying case US$530 – 256GB internal storage, faster storage, carrying case, Exclusive Steam Community profile bundle. termux cc checker. firewood processor rental near me; Steam deck.
Enmnl7W. Mô hình lập trình đồng thời và lập trình song song Thời gian đầu, CPU chỉ có một nhân duy nhất, các ngôn ngữ khi đó sẽ theo mô hình lập trình tuần tự, điển hình là ngôn ngữ C. Ngày nay, với sự phát triển của công nghệ đa xử lý, để tận dụng tối đa sức mạnh của CPU, mô hình lập trình song song hay multi-threading thường thấy trên các ngôn ngữ lập trình ra đời. Ngôn ngữ Go cũng phát triển mô hình lập trình đồng thời rất hiệu quả với khái niệm Goroutines. Lập trình tuần tự Lập trình song song Ở phần này chúng ta sẽ đi tìm hiểu về mô hình lập trình đồng thời trong Golang như thế nào. Trước hết chúng ta cùng nhắc lại một số kiến thức liên quan đến xử lý đồng thời và xử lý song song parallelism. Xử lý đồng thời là khả năng phân chia và điều phối nhiều tác vụ khác nhau trong cùng một khoảng thời gian và tại một thời điểm chỉ có thể xử lý một tác vụ. Khái niệm này trái ngược với xử lý tuần tự sequential processing. Xử lý tuần tự là khả năng xử lý chỉ một tác vụ trong một khoảng thời gian, các tác vụ sẽ được thực thi theo thứ tự hết tác vụ này sẽ thực thi tiếp tác vụ khác. Concurrency is about dealing with lots of things at once-Rob Pike Ví dụ như chúng ta vừa muốn nghe nhạc vừa đọc Advanced Go book và trong lúc đọc bạn muốn tải bộ tài liệu về từ zalopay-oss. Nếu như theo mô hình xử lý tuần tự thì trìng duyệt web sẽ phải thực hiện việc nghe nhạc xong, rồi tới việc mở Advanced Go book online để đọc và sau khi đọc xong chúng ta mới có thể tải về được. Đối với mô hình xử lý đồng thời thì ta có thể làm 3 tác vụ trên trong cùng một khoảng thời gian. Chúng ta có thể vừa nghe nhạc vừa lướt đọc tài liệu mà vừa có thể tải bộ tài liệu này về máy. Vậy làm thế nào để có thể xử lý đồng thời như vậy ? Tất cả các chương trình đang chạy trong máy tính chúng ta chạy đều do hệ điều hành quản lý, với mỗi chương trình đang chạy như vậy được gọi là một process tiến trình và được cấp một process id PID để hệ điều hành dễ dàng quản lí. Các tác vụ của tiến trình sẽ được CPU core nhân CPU của máy tính xử lý. Vậy làm sao 1 máy tính có CPU 1 nhân có thể làm được việc xử lý đồng thời nhiều tác vụ của các tiến trình cùng lúc. Bởi vì bản chất tại một thời điểm nhân CPU chỉ có thể xử lý một tác vụ. Như câu nói của Rob Pike, ông đã sử dụng từ dealing phân chia xử lý để nói đến khái niệm concurrency. Thật như vậy, nhân CPU không bao giờ đợi xử lý xong một tác vụ rồi mới xử lý tiếp tác vụ khác, mà nhân CPU đã chia các tác vụ lớn thành các tác vụ nhỏ hơn và sắp xếp xen kẽ lẫn nhau. Nhân CPU xẽ tận dụng thời gian rảnh của tác vụ này để đi làm tác vụ khác, một lúc thì làm tác vụ nhỏ này, một lúc khác thì làm tác vụ nhỏ khác. Như vậy chúng ta sẽ cảm thấy máy tính xử lý nhiều việc cùng lúc tại cùng thời điểm. Nhưng bản chất bên dưới nhân CPU thì nó chỉ có thể thực thi một tác vụ nhỏ trong tác vụ lớn tại thời điểm đó. Chia nhỏ tác vụ và xử lý trong mô hình concurrency Mô hình xử lý tuần tự Xử lý song song là gì ? Xử lý song song là khả năng xử lý nhiều tác vụ khác nhau trong cùng một thời điểm, các tác vụ này hoàn toàn độc lập với nhau. Xử lý song song chỉ có thể thực hiện trên máy tính có số nhân lớn hơn 1. Thay vì một nhân CPU chúng ta chỉ có thể xử lý một tác vụ nhỏ tại một thời điểm thì khi số nhân CPU có nhiều hơn chúng ta có thể xử lý các tác vụ song song với nhau cùng lúc trên các nhân CPU. Parallelism is about doing lots of things at once-Rob Pike Cũng lấy ví dụ nghe nhạc, đọc tài liệu và tải tài liệu ở trên, thì trong mô hình xử lý song song sẽ như sau. Mô hình xử lý song song các tác vụ cùng một thời điểm Trong thực tế, trên mỗi nhân của CPU vẫn xảy ra quá trình xử lý đồng thời miễn là tại một thời điểm không có xảy ra việc xử lý cùng một tác vụ trên hai nhân CPU khác nhau, mô hình trên vẽ lại như sau Mô hình xử lý song song Chúng ta nên nắm được mô hình xử lý đồng thời khác với mô hình xử lý song song, tuy hai mô hình đều nêu lên việc xử lý nhiều tác vụ trong cùng một thời điểm. Trong một bài diễn thuyết của Rob Pike, ông cũng đã trình bày và phân biệt hai mô hình trên. Các bạn có thể xem buổi diễn thuyết ở đây. Xử lý đồng thời trong Golang Trước khi tìm hiểu về cách Golang xử lý đồng thời như thế nào, chúng ta cùng nhắc lại một số khái niệm về tiến trình process và luồng thread trong hệ điều hành. Process Tiến trình có thể hiểu đơn giản là một chương trình đang chạy trong máy tính. Khi chúng ta mở trình duyệt web để đọc Advanced Go book thì đây được xem là một tiến trình. Khi chúng ta viết 1 chương trình máy tính bằng ngôn ngữ lập trình như C, Java, hay Go, sau khi tiến hành biên dịch và chạy chương trình thì hệ điều hành sẽ cấp cho chương trình một không gian bộ nhớ nhất định, PID process ID,... Mỗi tiến trình có ít nhất một luồng chính main thread để chạy chương trình, nó như là xương sống của chương trình vậy. Khi luồng chính này ngừng hoạt động tương ứng với việc chương trình bị tắt. Thread Thread hay được gọi là tiểu trình nó là một luồng trong tiến trình đang chạy. Các luồng được chạy song song trong mỗi tiến trình và có thể truy cập đến vùng nhớ được cung cấp bởi tiến trình, các tài nguyên của hệ điều hành,... Mô hình xử lý song song Các thread trong process sẽ được cấp phát riêng một vùng nhớ stack để lưu các biến riêng của thread đó. Stack được cấp phát cố định khoảng 1MB-2MB. Ngoài ra các thread chia sẻ chung vùng nhớ heap của process. Khi process tạo quá nhiều thread sẽ dẫn đến tình trạng stack overflow. Khi các thread sử dụng chung vùng nhớ sẽ dễ gây ra hiện tượng race condition. Ở phần sau chúng ta sẽ tìm hiểu cách Golang xử lý như thế nào để tránh lỗi race condition. Ở các phần trên chúng ta đã cùng nhau thảo luận về mô hình xử lý đồng thời và xử lý song song các tác vụ, các tác vụ ở đây sẽ được thực hiện bởi các thread khác nhau. Vì vậy tương quan ở đây là khi chúng ta xử lý các tác vụ theo mô hình đồng thời hay song song cũng có nghĩa là có nhiều thread chạy đồng thời hay song song multi-threading. Số lượng thread chạy song song trong cùng một thời điểm sẽ bằng với số lượng nhân CPU mà máy tính chúng ta có. Vì vậy khi chúng ta lập trình mà tạo quá nhiều thread thì cũng không có giúp cho chương trình chúng ta chạy nhanh hơn, mà còn gây ra lỗi và làm chậm chương trình. Theo kinh nghiệm lập trình chúng ta chỉ nên tạo số thread bằng số nhân CPU * 2. Như mình đã trình bày ở phần trên thì khi xử lý đồng thời thì tại một thời điểm chỉ có một tác vụ được xử lý hay một thread được chạy trên một nhân CPU. Khi nhân CPU chuyển qua xử lý tác vụ khác cũng có nghĩa là thread khác được chạy. Thao tác đó được gọi là context switch. Các bạn có thể xem chi tiết ở đây. Goroutines và system threads Goroutines là một đơn vị concurrency của ngôn ngữ Go. Hay nói cách khác Golang sử dụng goroutine để xử lý đồng thời nhiều tác vụ. Việc khởi tạo goroutines sẽ ít tốn chi phí hơn khởi tạo thread so với các ngôn ngữ khác. Cách khởi tạo goroutine chỉ đơn giản thông qua từ khóa go. Về góc nhìn hiện thực, goroutines và thread không giống nhau. Đầu tiên, system thread sẽ có một kích thước vùng nhớ stack cố định thông thường vào khoảng 2MB. Vùng nhớ stack chủ yếu được dùng để lưu trữ những tham số, biến cục bộ và địa chỉ trả về khi chúng ta gọi hàm. Kích thước cố định của stack sẽ dẫn đến hai vấn đề Stack overflow với những chương trình gọi hàm đệ quy sâu. Lãng phí vùng nhớ đối với chương trình đơn giản. Giải pháp cho vấn đề này chính là cấp phát linh hoạt vùng nhớ stack Một Goroutines sẽ được bắt đầu bằng một vùng nhớ nhỏ khoảng 2KB hoặc 4KB. Khi gọi đệ quy sâu không gian stack hiện tại là không đủ Goroutines sẽ tự động tăng không gian stack kích thước tối đa của stack có thể được đạt tới 1GB. Bởi vì chi phí của việc khởi tạo là nhỏ, chúng ta có thể dễ dàng giải phóng hàng ngàn goroutines. Với ngôn ngữ lập trình khác như Java thì các thread được quản lý bởi hệ điều hành, có nghĩa là chương trình chúng ta đang xử lý đồng thời bị phụ thuộc vào hệ điều hành. Trong Golang sử dụng Go runtime có riêng cơ chế định thời cho Goroutines, nó dùng một số kỹ thuật để ghép M Goroutines trên N thread của hệ điều hành. Cơ chế định thời Goroutines tương tự với cơ chế định thời của hệ điều hành nhưng chỉ ở mức chương trình. Biến quy định số lượng thread hiện thời chạy trên các Goroutines. Chúng ta cùng xem qua bảng so sánh giữa Gorountines và Thread được tham khảo ở đây Mô hình xử lý song song Ví dụ Goroutine Ví dụ 1 func main { // sử dụng từ khoá go để tạo goroutine go chào goroutine" chào main goroutine " } Chương trình trên có lúc in ra cả hai câu không đúng như thứ tự trên, có lúc sẽ chỉ in được mỗi câu "Xin chào main goroutin". Chúng ta đã biết khi hàm main chạy xong thì chương trình sẽ dừng. Hàm main cũng là một goroutine và chạy đồng thời với hàm Nên có trường hợp hàm main chạy xong và dừng trước khi hàm được chạy. Chúng ta có thể làm như sau để có thể in ra cả hai câu func main { // sử dụng từ khoá go để tạo goroutine go from another goroutine" from main goroutine" // chờ 1 giây để có thể chạy được goroutine //của hàm trước khi hàm main kết thúc } Sau khi chương trình chạy xong các goroutine sẽ bị huỷ. Ví dụ 2 Chúng ta có thể sử dụng goroutine bằng cách sau. func MyPrintlnid int, delay { go func { chào, tôi là goroutine ", id } } func main { for i = 0; i < 100; i++ { MyPrintlni, 1* } * trình kết thúc" } Ở phần tiếp theo chúng ta sẽ đi tới những ví dụ phức tạp hơn như cách xử lý race-condition trong Golang, sử dụng channel để chặn các goroutine,... Liên kết Phần tiếp theo Mô hình thực thi đồng thời Phần trước Functions, Methods và Interfaces Mục lục
19/06/2021 Lập trình đa luồng luôn bị coi là một chủ đề phức tạp và đáng sợ. Tuy nhiên, rất khó né tránh chủ đề này khi app của chúng ta càng ngày càng thực hiện nhiều tác vụ mà vẫn phải đảm bảo trải nghiệm người dùng. Trong series này mình sẽ cùng các bạn khám phá mọi góc cạnh của đa luồng và biến nó trở thành công cụ đắc lực. Với bất kỳ kiến thức nào, nền tảng luôn là thứ quan trọng nhất. Vậy nên, mình sẽ dành phần đầu series để nói về cách thức hoạt động của CPU và hệ điều hành. Kiến thức này sẽ giúp ta hiểu rõ hơn về bản chất của lập trình đa luồng trong iOS CPU & Core CPU là bộ não của một thiết bị điện tử. Nó nhận lệnh từ hệ điều hành và biến chúng thành các tính toán cần thiết. CPU được cấu thành bởi một hoặc nhiều Core với chức năng thực hiện các tính toán trên. Chip M1 của Apple sở hữu CPU với 8 Core Mỗi Core chỉ có thể làm duy nhất một tác vụ một lúc. Hiểu một cách đơn giản, nếu CPU là bộ não, thì Core như cánh tay của nó. Mỗi tay chỉ làm một việc tại một thời điểm như cầm sách, quẹt điện thoại, hay di chuột. Theo logic trên, ta có thể suy ra số Core tỉ lệ thuận với số tác vụ được thực thi song song. Process & Thread CPU và Core là phần cứng, và hệ điều hành là phần mềm giúp ta giao tiếp với chúng. Trong iOS, một chương trình khi chạy được tạo nên bởi một process tương ứng. Process có nhiệm vụ cung cấp các tài nguyên, tập lệnh, và vùng nhớ cần thiết cho hoạt động của chương trình đó. Các process khác nhau chạy tách biệt và không dùng chung bất cứ dữ liệu nào. Gmail và Safari là 2 process độc lập Process sở hữu một hoặc nhiều luồng. Luồng, hay còn gọi là thread, là hàng chờ của các lệnh. Mỗi khi bạn gọi function như reloadData, hay tạo biến như let language = "swift", chúng sẽ biến thành chỉ dẫn cho CPU dưới dạng nhị phân và được đặt vào thread. Các thread sẽ chuyển những chỉ dẫn đó tới CPU và sau đó CPU sẽ sử dụng Core để thực thi và thay đổi trạng thái của process. Quay lại phép ẩn dụ ở phần trước, bạn hãy hình dung bộ não đang tung hứng nhiều quả bóng với 2 cánh tay, mỗi cánh tay chỉ có thể cầm một quả bóng và ngay sau đó phải đổi sang quả bóng khác. Những quả bóng ở đây chính là thread, và hành động tung hứng cũng giống việc CPU điều khiển các Core thực hiện chỉ dẫn trong thread đó. Một Core chỉ làm việc với một thread một lúc và chỉ xử lý một chỉ dẫn trong thread đó tại bất cứ thời điểm nào. Nguồn GIPHY Điều gì sẽ xảy ra khi số tay được tăng từ 2 lên 4? Nếu câu trả lời của bạn là bộ não giờ đây có thể cầm tối đa 4 quả bóng cùng lúc thì bạn đã hiểu chính xác rồi đấy. Nguồn GIPHY sorry, đây gif hợp lý nhất mình có thể tìm được Số thread trong một process không cố định. Process có thể huỷ hoặc sinh ra thread mới khi cần thiết. Các thread trong cùng một process chia sẻ vùng nhớ và dữ liệu với nhau. Dữ liệu ở đây có thể kể đến như object, function, con trỏ địa chỉ vùng nhớ, hoặc bất kì biến nào được tạo ra. Các thread khác nhau sở hữu độ ưu tiên khác nhau. CPU chạy thread dựa theo độ ưu tiên giảm dần. Mỗi process sở hữu một tập thread riêng. Các thread trong một process hoạt động trên cùng một vùng nhớ Trong iOS, ta không làm việc với process mà chỉ có thể tương tác với thread qua class Thread. Tuy nhiên, Thread là một API bậc thấp và yêu cầu người code phải xử lý rất nhiều chi tiết phức tạp. trường hợp, bạn nên tránh sử dụng nó trực tiếp. Hãy ưu tiên các API bậc cao như Grand Central Dispatch GCD hoặc Operation. Nếu bạn thấy GCD là một thuật ngữ xa lạ thì đừng sợ, thực ra đây là một API rất thân thuộc với chúng ta. Chắc hẳn bạn đã từng dùng rồi chứ 😉 Về bản chất, khi app khởi tạo, iOS sẽ cung cấp cho nó một thread chính, gọi là main thread. Code bạn viết ra mặc định chạy trên thread này. Đây cũng là thread bắt buộc phải dùng để gọi code liên quan tới UI. Bạn có thể truy cập main thread qua override func viewDidLoad { //code mặc định chạy trên main thread = self = self callAPI } func callAPI { //vẫn đang ở trên main thread let url = URLstring "domain"! url { data, res, err in //... //hiện đang không ở main thread //... { //quay lại main thread để cập nhật UI } } } Khi bạn gọi hoặc thì các dòng lệnh ở giữa 2 dấu { } sẽ được chạy trên main thread. Ta gọi chung những dòng lệnh đó là task. Từ giờ khi dùng thread là mình muốn ám chỉ thread của process, còn Thread để biểu thị class Thread trong swift Đa luồng - Multithreading Trang bị những kiến thức trên, chúng ta đã sẵn sàng tìm hiểu đa luồng và chi tiết cách CPU cùng các Core hoạt động với nó. Multithreading là gì? Multithreading là khả năng xử lý nhiều thread cùng lúc của CPU. Khi có nhiều task khác nhau, CPU có thể làm việc với chúng đồng thời - concurrent hoặc song song - parallel. Giả sử tồn tại task A với thời gian chạy 1 phút, và task B với thời gian chạy 2 phút. Hai task A, B chạy parallel nếu CPU xử lí chúng cùng thời điểm. Tổng thời gian cần để hoàn thành 2 task sẽ là thời gian chạy của task lâu nhất, tức maxA, B = 2 phút Hai task A, B chạy đồng thời nếu CPU xử lí chúng parallel hoặc chạy một phần của task A rồi đổi sang task B và cứ thể lặp lại cho đến khi 2 task hoàn thành. Tổng thời gian chạy có thể là maxA, B = 2 phút nếu chúng thực sự chạy parallel, hoặc A + B = 3 phút nếu CPU phải đổi giữa các task. 2-Core CPU có thể chạy 2 task A và B song song trong khi 1-Core CPU phải thay đổi liên tục giữa các task Nhắc lại kiến thức phần trước, Core là nơi thực hiện các task và mỗi Core chỉ chạy 1 task tại một thời điểm. Chính vì lí do này, 1-Core CPU chỉ có thể thực thi một task một lúc, và càng nhiều Core thì CPU càng thực hiện được nhiều task. Từ đây ta có thể hiểu concurrent là làm nhiều task cùng lúc. CPU không cần đợi task A hoàn thành để bắt đầu task B. Nó đạt được điều này bằng cách chạy các task đồng thời trên nhiều Core khác nhau, hoặc liên tục chuyển giữa chúng tại 1 Core. Parallel là trường hợp đặc biệt của concurrent, khi các task thực sự được cùng xử lý tại một thời điểm. Số task tối đa có thể chạy parallel chính bằng số Core của CPU. Về mặt hiệu năng, xử lý parallel giúp giảm thời gian hoàn thành task trong khi đối với concurrent thì điều này không được đảm bảo. Một điều cần lưu ý nữa là việc đổi giữa các task của các thread khác nhau không miễn phí. Khoảng xám giữa các lần đổi task là thời gian chuẩn bị cho task mới của CPU Để đổi task, hệ điều hành phải lưu trạng thái hiện giờ của CPU, xác định task mới, thiết lập trạng thái cho task mới, load các thông tin cần thiết vào bộ nhớ và cache, load các lệnh chưa chạy hoặc đang chạy dở, và cuối cùng mới có thể thực thi task đó. Chính vì lí do này, multithread phải được dùng một cách rất cẩn trọng và có suy nghĩ. Việc lạm dụng multithread sẽ phản tác dụng và làm chậm app của bạn thay vì tăng tốc cho nó. Tại sao cần multithreading Những năm 90, máy tính phổ thông chỉ có một Core duy nhất. Điều này có nghĩa nếu không có multithreading, bạn sẽ không thể vừa nghe nhạc vừa duyệt web, hoặc không thể vừa down phim vừa làm luận án. Rất may là điều đó không phải sự thật. CPU có tốc độ xử lý hàng nghìn triệu phép tính một giây, kết hợp với multithreading, 1-Core CPU cho chúng ta ảo giác rằng ta có thể cùng lúc thao tác nhiều việc dù thực chất nó chỉ đang luân phiên xử lý các tác vụ. Ngày nay, kể cả khi máy tính sở hữu nhiều Core hơn, việc multithreading bằng cách đổi task vẫn rất phổ biến. Lý do đơn giản bởi vì luôn có hàng trăm process khác nhau chạy ngầm trong máy tính của bạn. Trong thực tế, rất khó để biết chắc chắn được khi nào các tác vụ được chạy parallel hoặc concurrent vì điều này hoàn toàn phụ thuộc vào số Core, cơ chế hoạt động của từng CPU, và hệ điều hành. iOS không cho bạn lựa chọn giữa parallel và concurrent. Bạn chỉ có thể chuyển task cho thread và hệ thống sẽ thực thi chúng tuỳ theo hoàn cảnh. Vậy nên từ giờ trở đi, mình sẽ dùng thuật ngữ concurrency danh từ của concurrent để nói chung cho cả parallel và concurrent. Race condition Multithreading không chỉ có màu hồng. Nếu bạn đã từng phải debug những lỗi khó tái hiện, hoặc lỗi thi thoảng mới gặp thì rất nhiều khả năng chúng liên quan đến concurrency. Ở phần này bài viết, chúng ta sẽ cùng tìm hiểu một vấn đề kinh điển khi code đa luồng. Thread trong một process hoạt động trên cùng một vùng nhớ và chia sẻ hầu hết tài nguyên của process. Nếu tại một thời điểm, hai hoặc nhiều thread cùng truy cập và thay đổi một địa chỉ nhớ thì thứ tự truy cập của chúng sẽ ảnh hưởng đến kết quả bạn nhận được. Nói một cách khác, kết quả của tác vụ trở nên không thể đoán định và phụ thuộc vào trình tự chạy của các thread. Hiện tượng này được gọi là race condition. Hình dung bạn và một người lạ đang ở rạp phim và cùng có ý định mua vé xem Avengers. Điều gì sẽ xảy ra nếu 2 nhân viên quầy vé cùng nhấn nút một lúc? Có thể người mua được là bạn hoặc cũng có thể là người lạ kia. Nếu viễn cảnh đấy lặp lại 100 lần, không gì đảm bảo 100 lần đó kết quả đều như nhau. Trong thực tế, việc kết quả của các lệnh phụ thuộc vào sự kết hợp đan xen ngẫu nhiên của các thread gây ra rất nhiều rắc rối class UnsafeDataSource { private var model [Int] = [1, 2, 3] func removeAll { } func printFirstItem { if ! { printmodel[0] } } } Giả sử có hai thread A, B cùng đọc và thay đổi giá trị của UnsafeDataSource, thread A gọi function removeAll để xoá hết item trong model, còn thread B in item đầu tiên sau khi kiểm tra model không rỗng. Trong trường hợp A chạy xong hoàn toàn rồi mới đến B, không có gì được in ra. Nếu B chạy trước A, model[0] sẽ được in trước khi A xoá item trong model. Tuy nhiên, do trình tự thực thi của các thread không thể đoán định, hoàn toàn có khả năng B vừa check isEmpty xong thì CPU đổi sang thread A và chạy lệnh removeAll. Lúc này sẽ xảy ra crash khi CPU quay lại thread B để chạy lệnh printmodel[0] vì mặc dù B đã check isEmpty là false, điều này không còn đúng tại thời điểm model[0] thực thi vì toàn bộ item đã bị xoá Race condition khi nhiều thread cùng làm việc với UnsafeDataSource Một trường hợp hay gặp gây ra bởi race condition là Fatal error Index out of range ở hàm cellForRowat indexPath khi Nguyên nhân là do trạng thái của UITableView không đồng nhất với model do hàm reloadData và cellForRow truy cập model ở trên main thread nhưng trong lúc đó model lại bị thay đổi ở một thread khác. Class và struct bạn tạo ra mặc định không an toàn để sử dụng đa luồng. Nếu biến và các thuộc tính của chúng có thể bị thay đổi bởi bất kì thread nào thì race condition chắc chắn sẽ xảy ra. Code chạy đúng 1000 lần không có nghĩa bạn sẽ an toàn ở lần thứ 1001. Value type trong swift không phải lúc nào cũng an toàn để sử dụng đa luồng Tổng kết Chúng ta đã cùng nhau hiểu rõ hơn về cách hoạt động của CPU, Core, cũng như cách chúng kết hợp với iOS để chạy code của ứng dụng. Ta cũng biết thêm về một vấn đề nổi cộm trong multithreading là race condition. Ở những bài tiếp theo, mình sẽ nói kĩ hơn về cách sử dụng các API đa luồng trong iOS như DispatchQueue, Operation, và NSLock. Trong quá trình đó, bạn cũng sẽ được giới thiệu về các vấn đề của chúng như deadlock và priority inversion. Hẹn gặp lại ở bài viết tới ;
chạy song song 2 cpu