NSOperation vs Grand Central Công văn


465

Tôi đang tìm hiểu về lập trình đồng thời cho iOS. Cho đến nay tôi đã đọc về NSOperation/NSOperationQueueGCD. Các lý do để sử dụng NSOperationQueuehơn GCDvà ngược lại là gì?

Âm thanh như cả hai GCDNSOperationQueuetrừu tượng đi sự sáng tạo rõ ràng NSThreadstừ người dùng. Tuy nhiên, mối quan hệ giữa hai cách tiếp cận không rõ ràng đối với tôi vì vậy mọi phản hồi đều được đánh giá cao!


10
+1 cho câu hỏi hay - tò mò về kết quả. Cho đến nay, tôi chỉ đọc rằng GCD có thể dễ dàng được gửi đi qua các lõi CPU, khiến nó trở thành "shit nóng mới".
Đến

3
Một số thảo luận liên quan có thể được tìm thấy trong câu hỏi này: Tại sao tôi nên chọn GCD thay vì NSOperation và các khối cho các ứng dụng cấp cao?
Brad Larson

Câu trả lời:


517

GCDlà một API dựa trên C cấp thấp cho phép sử dụng mô hình tương tranh dựa trên nhiệm vụ rất đơn giản. NSOperationNSOperationQueuelà các lớp Objective-C làm một điều tương tự. NSOperationđã được giới thiệu đầu tiên, nhưng kể từ 10.5iOS 2 , NSOperationQueuevà bạn bè được triển khai nội bộ bằng cách sử dụng GCD.

Nói chung, bạn nên sử dụng mức độ trừu tượng cao nhất phù hợp với nhu cầu của bạn. Điều này có nghĩa là bạn thường nên sử dụng NSOperationQueuethay vì GCD, trừ khi bạn cần làm điều gì đó NSOperationQueuekhông hỗ trợ.

Lưu ý rằng đó NSOperationQueuekhông phải là phiên bản GCD "chết lặng"; trong thực tế, có rất nhiều điều mà bạn có thể làm rất đơn giản với NSOperationQueueđó là mất rất nhiều công việc với sự thuần khiết GCD. (Ví dụ: hàng đợi bị hạn chế băng thông chỉ chạy N hoạt động tại một thời điểm; thiết lập sự phụ thuộc giữa các hoạt động. Cả hai đều rất đơn giản NSOperation, rất khó với GCD.) Apple đã làm rất chăm chỉ khi tận dụng GCD để tạo API thân thiện với đối tượng NSOperation. Tận dụng công việc của họ trừ khi bạn có lý do để không.

Nên biết trước : Mặt khác, nếu bạn thực sự chỉ cần gửi đi một khối, và không cần bất kỳ chức năng bổ sung mà NSOperationQueuecung cấp, không có gì sai với việc sử dụng GCD. Chỉ cần chắc chắn rằng đó là công cụ phù hợp cho công việc.


1
NSOperation để được cụ thể một lớp trừu tượng.
Roshan

3
@Sandy Thực tế thì ngược lại, GCD được NSOperation sử dụng (ít nhất là trong các phiên bản sau của iOS và OS X).
garrettmoon

1
@BJ Homer Chúng ta có thể thêm tác vụ trong hàng đợi công văn nối tiếp để giảm bớt sự suy giảm. Vì vậy, chỉ cần làm thế nào hàng đợi hoạt động có lợi thế hơn
Raj Aggrawal

3
@RajAggrawal Có, nó hoạt động được nhưng sau đó bạn bị mắc kẹt với hàng đợi nối tiếp. NSOperation có thể thực hiện "thực hiện thao tác này sau khi ba điều còn lại được thực hiện, nhưng đồng thời với tất cả những thứ khác đang diễn ra." Phụ thuộc hoạt động thậm chí có thể tồn tại giữa các hoạt động trên các hàng đợi khác nhau. Hầu hết mọi người sẽ không cần điều đó, nhưng nếu bạn làm thế, NSOperation sẽ là lựa chọn tốt hơn.
BJ Homer

369

Phù hợp với câu trả lời của tôi cho một câu hỏi liên quan , tôi sẽ không đồng ý với BJ và đề nghị bạn nên xem GCD trước NSOperation / NSOperationQueue, trừ khi sau này cung cấp thứ bạn cần mà GCD không có.

Trước GCD, tôi đã sử dụng rất nhiều NSOperations / NSOperationQueues trong các ứng dụng của mình để quản lý đồng thời. Tuy nhiên, vì tôi bắt đầu sử dụng GCD một cách thường xuyên, tôi gần như đã thay thế hoàn toàn NSOperations và NSOperationQueues bằng các khối và gửi hàng đợi. Điều này xuất phát từ cách tôi sử dụng cả hai công nghệ trong thực tế và từ hồ sơ tôi đã thực hiện trên chúng.

Đầu tiên, có một lượng chi phí không cần thiết khi sử dụng NSOperations và NSOperationQueues. Đây là những đối tượng Ca cao, và chúng cần được phân bổ và giải quyết. Trong một ứng dụng iOS mà tôi đã viết để hiển thị cảnh 3 chiều ở 60 FPS, tôi đã sử dụng NSOperations để gói gọn từng khung hình được hiển thị. Khi tôi mô tả điều này, việc tạo và phá vỡ các NSOperations này đã chiếm một phần đáng kể trong các chu kỳ CPU trong ứng dụng đang chạy và làm mọi thứ chậm lại. Tôi đã thay thế chúng bằng các khối đơn giản và hàng đợi nối tiếp GCD và chi phí đó biến mất, dẫn đến hiệu suất hiển thị tốt hơn đáng kể. Đây không phải là nơi duy nhất tôi nhận thấy chi phí sử dụng NSOperations và tôi đã thấy điều này trên cả Mac và iOS.

Thứ hai, có một sự tao nhã đối với mã công văn dựa trên khối khó khớp khi sử dụng NSOperations. Thật tiện lợi vô cùng khi bọc một vài dòng mã trong một khối và gửi nó đi được thực hiện trên hàng đợi nối tiếp hoặc đồng thời, trong đó việc tạo NSOperation hoặc NSInvocationOperation tùy chỉnh để thực hiện điều này đòi hỏi nhiều mã hỗ trợ hơn. Tôi biết rằng bạn có thể sử dụng NSBlockOperation, nhưng sau đó bạn cũng có thể gửi một cái gì đó đến GCD. Việc gói mã này trong các khối nội tuyến với xử lý có liên quan trong ứng dụng của tôi theo ý kiến ​​của tôi để tổ chức mã tốt hơn so với việc có các phương thức riêng biệt hoặc NSOperations tùy chỉnh đóng gói các tác vụ này.

NSOperations và NSOperationQueues vẫn có những ứng dụng rất tốt. GCD không có khái niệm thực sự về các phụ thuộc, trong đó NSOperationQueues có thể thiết lập các biểu đồ phụ thuộc khá phức tạp. Tôi sử dụng NSOperationQueues cho điều này trong một số ít trường hợp.

Nhìn chung, trong khi tôi thường ủng hộ việc sử dụng mức độ trừu tượng cao nhất để hoàn thành nhiệm vụ, thì đây là một trường hợp tôi tranh luận về API GCD cấp thấp hơn. Trong số các nhà phát triển iOS và Mac mà tôi đã nói về vấn đề này, đại đa số chọn sử dụng GCD thay vì NSOperations trừ khi họ nhắm mục tiêu các phiên bản HĐH mà không hỗ trợ cho nó (những phiên bản trước iOS 4.0 và Snow Leopard).


20
Tôi chỉ không đồng ý nhẹ; Tôi sử dụng GCD đơn giản một chút. Nhưng tôi nghĩ bạn giảm giá NSBlockOperation quá nhiều trong câu trả lời này. Tất cả các lợi ích của NSOperationQueue (phụ thuộc, khả năng gỡ lỗi, v.v.) cũng áp dụng cho các hoạt động khối.
BJ Homer

4
@BJHomer - Tôi nghĩ rằng việc tránh NSBlockOperation là vấn đề sở thích cá nhân trong trường hợp của tôi, mặc dù tôi đã tránh xa NSOperations nói chung sau khi thấy chi phí sử dụng kéo xuống một vài ứng dụng. Nếu tôi sẽ sử dụng các khối, tôi có xu hướng sử dụng toàn bộ GCD, ngoại trừ khi tôi cần hỗ trợ phụ thuộc.
Brad Larson

1
+1, cảm ơn vì phân tích này. Apple dường như đang ủng hộ cả hai (như phiên của WWDC 2012 về giao diện người dùng đồng thời), vì vậy điều này được đánh giá cao.
orip

1
@VolureDarkAngel - GCD cực kỳ nhanh trong việc xử lý các công văn như thế. Nó không phải là nút cổ chai của bạn trong một tình huống như bạn mô tả, trừ khi bạn bằng cách nào đó sao lưu một đống cập nhật vào hàng đợi do truy cập I / O chậm hoặc một cái gì đó thuộc loại này. Có lẽ đó không phải là trường hợp ở đây.
Brad Larson

1
@ asma22 - Việc tính toán có thể được thực hiện theo từng khối là điều phổ biến, nhưng tính toán cuối cùng của một giai đoạn có thể cần kết quả từ một số giai đoạn trước. Trong trường hợp đó, bạn có thể thực hiện thao tác sau đó phụ thuộc vào các hoạt động trước đó và việc lập lịch sẽ được quản lý sao cho tất cả các hoạt động hoàn thành trước khi hoạt động cuối cùng chạy.
Brad Larson

101

GCDlà một API dựa trên C cấp thấp.
NSOperationNSOperationQueuelà các lớp Objective-C.
NSOperationQueuelà mục tiêu C bao bọc hơn GCD. Nếu bạn đang sử dụng NSOperation, thì bạn đang sử dụng Grand Central Dispatch.

Lợi thế của GCD so với NSOperation:
i. thực hiện
Để GCDthực hiện rất nhẹ trọng lượng
NSOperationQueuelà phức tạp và nặng

Ưu điểm của NSOperation so với GCD:

Tôi. Kiểm soát hoạt động
bạn có thể tạm dừng, hủy, tiếp tụcNSOperation

ii. Các phụ thuộc
bạn có thể thiết lập một phụ thuộc giữa hai NSOperations
thao tác sẽ không bắt đầu cho đến khi tất cả các phụ thuộc của nó trở lại đúng cho kết thúc.

iii. Trạng thái hoạt động
có thể giám sát trạng thái của một hàng đợi hoạt động hoặc hoạt động. sẵn sàng, thực hiện hoặc kết thúc

iv. Số lượng hoạt động
tối đa bạn có thể chỉ định số lượng hoạt động được xếp hàng tối đa có thể chạy đồng thời

Khi nào nên sử dụng GCDhoặcNSOperation
khi nào bạn muốn kiểm soát nhiều hơn đối với hàng đợi (tất cả đã đề cập ở trên) NSOperation và trong các trường hợp đơn giản mà bạn muốn ít chi phí hơn (bạn chỉ muốn thực hiện một số công việc "vào nền" với rất ít công việc bổ sung) sử dụngGCD

ref:
https://cocoacasts.com/ch rủi-b between-nsoperation-and-grand-central-dispatch / http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html http : //nshipster.com/nsoperation/


Như đã nói, số lượng hoạt động tối đa có thể được chỉ định trong NSOperationQueue, vậy thì số lượng hoạt động tối đa (hàng đợi gửi) trong GCD là bao nhiêu? Giả sử tôi có một dự án, thì tôi có thể thực hiện bao nhiêu thao tác (gửi hàng đợi). hoặc của họ là bất kỳ giới hạn tối đa mà chúng ta có thể làm.
Roshan Sah

Nó phụ thuộc vào các điều kiện hệ thống ở đây là thông tin chi tiết: stackoverflow.com/questions/14995801/
Khăn

Chúng tôi cũng có thể hủy tác vụ trong GCD bằng cách sử dụng DispatchWorkItem và chúng tôi cũng có thể tạm dừng và tiếp tục
Ankit garg

@Ankitgarg Gọi hủy trên DispatchWorkItem sẽ ngăn các tác vụ thực thi nếu chúng chưa được chạy, nhưng sẽ không dừng một cái gì đó đã được thực thi. và làm thế nào để bạn tạm dừng / tiếp tục một DispatchWorkItem ??
abhimuralidharan

34

Một lý do khác để thích NSOperation hơn GCD là cơ chế hủy bỏ của NSOperation. Ví dụ: Ứng dụng như 500px hiển thị hàng tá ảnh, sử dụng NSOperation, chúng tôi có thể hủy yêu cầu của các ô hình ảnh vô hình khi chúng tôi cuộn chế độ xem bảng hoặc chế độ xem bộ sưu tập, điều này có thể cải thiện đáng kể hiệu suất Ứng dụng và giảm dấu chân bộ nhớ. GCD không thể dễ dàng hỗ trợ này.

Ngoài ra với NSOperation, KVO có thể có thể.

Đây là một bài viết từ Eschaton rất đáng đọc.


4
Điều đáng chú ý là nếu những gì bạn đang hủy là hoạt động mạng của việc tải hình ảnh, thì bạn không cần NSOperationđiều này, NSURLSessionTask.cancelNSURLSession.invalidateAndCancelcung cấp chức năng này. Nói chung, NSURLSessioncung cấp một số chức năng của một NSOperationQueue, như NSURLSessionTaskcung cấp một số chức năng của mộtNSOperation
tảo

@acheal Như đã giải thích ở đây ( stackoverflow.com/questions/21918722/iêu ), có vẻ như NSURLSession sử dụng NSOperationQueue làm một khối xây dựng.
kalan nawarathne

33

GCD thực sự ở cấp độ thấp hơn NSOperationQueue, ưu điểm chính của nó là việc triển khai rất nhẹ và tập trung vào các thuật toán và hiệu suất không khóa.

NSOperationQueue cung cấp các cơ sở không có sẵn trong GCD, nhưng chúng có chi phí không hề nhỏ, việc triển khai NSOperationQueue rất phức tạp và nặng nề, liên quan đến việc khóa rất nhiều và chỉ sử dụng GCD trong nội bộ rất ít.

Nếu bạn cần các phương tiện do NSOperationQueue cung cấp bằng mọi cách sử dụng nó, nhưng nếu GCD đủ cho nhu cầu của bạn, tôi khuyên bạn nên sử dụng trực tiếp để có hiệu suất tốt hơn, giảm đáng kể CPU và chi phí điện năng và linh hoạt hơn.


24

Cả NSQueueOperations và GCD đều cho phép thực thi tác vụ tính toán nặng nề trong nền trên các luồng riêng biệt bằng cách giải phóng Tread chính của ứng dụng UI.

Vâng, dựa trên bài đăng trước, chúng tôi thấy NSOperations có addDependency để bạn có thể xếp hàng hoạt động của mình lần lượt theo thứ tự khác.

Nhưng tôi cũng đọc về Hàng đợi nối tiếp GCD mà bạn có thể tạo chạy các hoạt động của mình trong hàng đợi bằng cách sử dụng Clark_queue_create. Điều này sẽ cho phép chạy một tập hợp các hoạt động lần lượt theo cách thức liên tục.

NSQueueOperation Ưu điểm so với GCD:

  1. Nó cho phép thêm phụ thuộc và cho phép bạn loại bỏ sự phụ thuộc để cho một giao dịch bạn có thể chạy tuần tự bằng cách sử dụng phụ thuộc và cho giao dịch khác chạy đồng thời trong khi GCD không cho phép chạy theo cách này.

  2. Thật dễ dàng để hủy bỏ một hoạt động nếu nó nằm trong hàng đợi, nó có thể bị dừng nếu nó đang chạy.

  3. Bạn có thể xác định số lượng hoạt động đồng thời tối đa.

  4. Bạn có thể tạm dừng hoạt động mà họ đang ở trong Hàng đợi

  5. Bạn có thể tìm thấy có bao nhiêu hoạt động đang chờ xử lý trong hàng đợi.


6

GCD rất dễ sử dụng - nếu bạn muốn làm một cái gì đó trong nền, tất cả những gì bạn cần làm là viết mã và gửi nó trên một hàng đợi nền. Làm điều tương tự với NSOperation là rất nhiều công việc bổ sung.

Ưu điểm của NSOperation là (a) bạn có một đối tượng thực sự mà bạn có thể gửi tin nhắn đến và (b) rằng bạn có thể hủy NSOperation. Điều đó không tầm thường. Bạn cần phân lớp NSOperation, bạn phải viết mã chính xác để hủy bỏ và hoàn thành chính xác một tác vụ cả hai hoạt động chính xác. Vì vậy, đối với những điều đơn giản, bạn sử dụng GCD và đối với những điều phức tạp hơn, bạn tạo một lớp con của NSOperation. (Có các lớp con NSInvocationOperation và NSBlockOperation, nhưng mọi thứ họ làm được thực hiện dễ dàng hơn với GCD, vì vậy không có lý do chính đáng để sử dụng chúng).


3

Chà, NSOperations chỉ đơn giản là một API được xây dựng dựa trên Grand Central Dispatch. Vì vậy, khi bạn đang sử dụng NSOperations, bạn thực sự vẫn đang sử dụng Grand Central Dispatch. Chỉ là NSOperations cung cấp cho bạn một số tính năng ưa thích mà bạn có thể thích. Bạn có thể thực hiện một số thao tác phụ thuộc vào các hoạt động khác, sắp xếp lại hàng đợi sau khi bạn hoàn thành các mục và những thứ khác như thế. Trên thực tế, ImageGrabber đã sử dụng NSOperations và hàng đợi hoạt động! ASIHTTPRequest sử dụng chúng dưới mui xe và bạn có thể định cấu hình hàng đợi hoạt động mà nó sử dụng cho các hành vi khác nhau nếu bạn muốn. Vậy bạn nên sử dụng loại nào? Bất cứ điều gì có ý nghĩa cho ứng dụng của bạn. Đối với ứng dụng này, nó khá đơn giản vì vậy chúng tôi chỉ cần sử dụng Grand Central Dispatch trực tiếp, không cần các tính năng ưa thích của NSOperation. Nhưng nếu bạn cần chúng cho ứng dụng của mình, hãy sử dụng nó!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.