NSOperation กับ Grand Central Dispatch


465

ฉันเรียนรู้เกี่ยวกับการเขียนโปรแกรมพร้อมกันสำหรับ iOS จนถึงขณะนี้ผมได้อ่านเกี่ยวกับNSOperation/NSOperationQueueGCDและ อะไรคือสาเหตุของการใช้NSOperationQueueเกินGCDและในทางกลับกัน?

เสียงเหมือนทั้งนามธรรมGCDและNSOperationQueueแยกออกไปสร้างที่ชัดเจนNSThreadsจากผู้ใช้ อย่างไรก็ตามความสัมพันธ์ระหว่างสองแนวทางนี้ไม่ชัดเจนสำหรับฉันดังนั้นข้อเสนอแนะใด ๆ ที่จะชื่นชม!


10
+1 สำหรับคำถามที่ดี - อยากรู้เกี่ยวกับผลลัพธ์ จนถึงตอนนี้ฉันเพิ่งอ่านว่า GCD สามารถส่งผ่านแกนกลางของ CPU ได้อย่างง่ายดายทำให้กลายเป็น "อึร้อนใหม่"
จนถึง


คำตอบ:


517

GCDเป็น C-based API ระดับต่ำที่ช่วยให้ใช้โมเดลการทำงานพร้อมกันได้ง่ายมาก NSOperationและNSOperationQueueเป็นคลาส Objective-C ที่ทำสิ่งเดียวกัน NSOperationเป็นครั้งแรก แต่เป็นของ10.5และiOS 2 , NSOperationQueueและเพื่อน ๆ GCDจะดำเนินการภายในโดยใช้

โดยทั่วไปคุณควรใช้สิ่งที่เป็นนามธรรมในระดับสูงสุดที่ตรงกับความต้องการของคุณ ซึ่งหมายความว่าคุณควรใช้NSOperationQueueแทนGCDเว้นแต่คุณจะต้องทำสิ่งที่NSOperationQueueไม่สนับสนุน

โปรดทราบว่าNSOperationQueueไม่ใช่ GCD รุ่น "โง่ลง" ในความเป็นจริงมีหลายสิ่งที่คุณสามารถทำได้มากเพียงกับการใช้เวลาที่มากของการทำงานที่มีความบริสุทธิ์NSOperationQueue GCD(ตัวอย่าง: คิวที่ จำกัด แบนด์วิดท์ที่เรียกใช้การดำเนินงาน N ครั้งเท่านั้นการสร้างการพึ่งพาระหว่างการดำเนินการทั้งง่ายNSOperationและยากมากด้วยGCD) Apple ได้ทำงานอย่างหนักในการใช้ประโยชน์จาก GCD เพื่อสร้าง API ที่เป็นมิตรกับNSOperationวัตถุ ใช้ประโยชน์จากงานของพวกเขาจนกว่าคุณจะไม่มีเหตุผล

Caveat : ในทางกลับกันถ้าคุณเพียงแค่ต้องการส่งบล็อกและไม่ต้องการฟังก์ชั่นเพิ่มเติมใด ๆ ที่NSOperationQueueมีให้คุณไม่จำเป็นต้องใช้ GCD เพียงให้แน่ใจว่าเป็นเครื่องมือที่เหมาะสมสำหรับงาน


1
NSOperation เป็นคลาสนามธรรมที่เฉพาะเจาะจง
Roshan

3
@Sandy มันตรงกันข้ามจริง ๆ แล้ว GCD นั้นถูกใช้โดย NSOperation (อย่างน้อยก็ใน iOS และ OS X เวอร์ชันใหม่กว่า)
garrettmoon

1
@BJ Homer เราสามารถเพิ่มงานในคิวการจัดส่งแบบอนุกรมเพื่อให้ได้รับความไม่พอใจ เพียงแค่วิธีการที่คิวการดำเนินงานมีความได้เปรียบมากกว่านั้น
Raj Aggrawal

3
@RajAggrawal ใช่มันใช้งานได้ ... แต่แล้วคุณก็ติดอยู่กับคิวอนุกรม NSOperation สามารถทำ "ดำเนินการการดำเนินการนี้หลังจากที่ทำสามอย่างเสร็จสิ้น แต่พร้อมกันกับสิ่งอื่น ๆ ที่เกิดขึ้น" การพึ่งพาการดำเนินการสามารถมีอยู่ระหว่างการดำเนินการกับคิวที่แตกต่างกัน คนส่วนใหญ่ไม่ต้องการสิ่งนั้น แต่ถ้าคุณทำ NSOperation จะเป็นทางเลือกที่ดีกว่า
BJ Homer

369

เพื่อให้สอดคล้องกับคำตอบของคำถามที่เกี่ยวข้องฉันจะไม่เห็นด้วยกับ BJ และแนะนำให้คุณดู GCD เป็นครั้งแรกเกี่ยวกับ NSOperation / NSOperationQueue ยกเว้นกรณีหลังนั้นจะมีบางสิ่งที่คุณต้องการที่ GCD ไม่ต้องการ

ก่อน GCD ฉันใช้ NSOperations / NSOperationQueues จำนวนมากในแอปพลิเคชันของฉันเพื่อจัดการภาวะพร้อมกัน อย่างไรก็ตามตั้งแต่ฉันเริ่มใช้ GCD เป็นประจำฉันได้เปลี่ยน NSOperations และ NSOperationQueues เกือบทั้งหมดด้วยบล็อกและส่งคิว สิ่งนี้มาจากวิธีที่ฉันใช้ทั้งสองเทคโนโลยีในทางปฏิบัติและจากการทำโปรไฟล์ที่ฉันได้ทำกับพวกเขา

อย่างแรกคือมีจำนวนค่าใช้จ่ายที่ไม่สำคัญเมื่อใช้ NSOperations และ NSOperationQueues นี่คือวัตถุโกโก้และจำเป็นต้องจัดสรรและยกเลิกการจัดสรร ในแอปพลิเคชัน iOS ที่ฉันเขียนซึ่งแสดงฉาก 3 มิติที่ 60 FPS ฉันใช้ NSOperations เพื่อแค็ปซูลเฟรมที่แสดงผลแต่ละเฟรม เมื่อฉันทำสิ่งนี้การสร้างและการลดลงของ NSOperations เหล่านี้เป็นส่วนสำคัญของรอบการทำงานของ CPU ในแอปพลิเคชันที่ทำงานอยู่และทำให้สิ่งต่าง ๆ ช้าลง ฉันแทนที่สิ่งเหล่านี้ด้วยบล็อกอย่างง่ายและคิวอนุกรม GCD และค่าใช้จ่ายดังกล่าวหายไป นี่ไม่ใช่สถานที่เดียวที่ฉันสังเกตเห็นค่าใช้จ่ายจากการใช้ NSOperations และฉันเห็นสิ่งนี้ทั้งใน Mac และ iOS

ประการที่สองมีความสง่างามในการส่งรหัสตามบล็อกที่ยากที่จะจับคู่เมื่อใช้ NSOperations มันสะดวกอย่างไม่น่าเชื่อที่จะห่อโค้ดสองสามบรรทัดในบล็อกและส่งไปให้ดำเนินการในคิวแบบอนุกรมหรือแบบพร้อมกันซึ่งการสร้าง NSOperation หรือ NSInvocationOperation แบบกำหนดเองเพื่อทำสิ่งนี้ต้องการรหัสสนับสนุนที่มากขึ้น ฉันรู้ว่าคุณสามารถใช้ NSBlockOperation ได้ แต่คุณอาจส่งบางสิ่งไปยัง GCD การห่อโค้ดนี้ในบล็อกแบบอินไลน์ด้วยการประมวลผลที่เกี่ยวข้องในแอปพลิเคชันของคุณทำให้ฉันคิดว่าการจัดระเบียบโค้ดดีกว่าการมีวิธีแยกต่างหากหรือ NSOperations แบบกำหนดเองที่ห่อหุ้มงานเหล่านี้

NSOperations และ NSOperationQueues ยังคงมีการใช้งานที่ดีมาก GCD ไม่มีแนวคิดการพึ่งพาที่แท้จริงที่ NSOperationQueues สามารถตั้งค่ากราฟการพึ่งพาที่ซับซ้อนได้ ฉันใช้ NSOperationQueues สำหรับเรื่องนี้ในบางกรณี

โดยรวมแล้วในขณะที่ฉันมักจะสนับสนุนให้ใช้สิ่งที่เป็นนามธรรมในระดับสูงสุดซึ่งทำงานได้สำเร็จนี่เป็นกรณีหนึ่งที่ฉันโต้แย้ง API ระดับล่างของ GCD ในบรรดานักพัฒนา iOS และ Mac ที่ฉันได้พูดคุยเกี่ยวกับเรื่องนี้ส่วนใหญ่เลือกที่จะใช้ GCD ผ่าน NSOperations เว้นแต่ว่าพวกเขาจะกำหนดเป้าหมายเวอร์ชันของระบบปฏิบัติการโดยไม่รองรับ (เช่นก่อน iOS 4.0 และ Snow Leopard)


20
ฉันไม่เห็นด้วยอย่างอ่อนโยนเท่านั้น ฉันใช้ GCD ธรรมดาค่อนข้างน้อย แต่ฉันคิดว่าคุณลด NSBlockOperation มากเกินไปในคำตอบนี้ ประโยชน์ทั้งหมดของ NSOperationQueue (การอ้างอิงการดีบักและอื่น ๆ ) นำไปใช้กับการบล็อกการทำงานด้วย
BJ Homer

4
@BJHomer - ฉันคิดว่าการหลีกเลี่ยง NSBlockOperation เป็นเรื่องของการตั้งค่าส่วนตัวในกรณีของฉันแม้ว่าฉันจะเบือนหน้าหนีจาก NSOperations โดยทั่วไปหลังจากเห็นค่าใช้จ่ายจากการใช้งานของพวกเขาลากลงสองสามแอปพลิเคชัน ถ้าฉันจะใช้บล็อคฉันมีแนวโน้มที่จะใช้ All-in กับ GCD ยกเว้นเมื่อฉันต้องการการสนับสนุนที่พึ่งพา
Brad Larson

1
+1 ขอบคุณสำหรับการวิเคราะห์นี้ Apple ดูเหมือนจะให้การสนับสนุนทั้งคู่ (เช่นเซสชันของ WWDC 2012 บน UI ที่เกิดขึ้นพร้อมกัน) ดังนั้นสิ่งนี้จึงเป็นที่นิยมอย่างมาก
orip

1
@VolureDarkAngel - GCD นั้นรวดเร็วมากในการจัดการเรื่องยื้อเช่นนั้น ไม่ควรเป็นคอขวดของคุณในสถานการณ์อย่างที่คุณอธิบายเว้นแต่คุณจะสำรองกองการปรับปรุงลงในคิวเนื่องจากการเข้าถึง I / O ที่ช้าหรือการเรียงลำดับบางอย่าง นั่นอาจไม่ใช่กรณีที่นี่
Brad Larson

1
@ asma22 - เป็นเรื่องปกติที่จะมีการคำนวณที่สามารถทำได้เป็นชิ้น ๆ แต่การคำนวณขั้นสุดท้ายของขั้นตอนเดียวอาจต้องการผลลัพธ์จากหลายขั้นตอนก่อนหน้า ในกรณีดังกล่าวคุณสามารถทำให้การดำเนินการในภายหลังนั้นขึ้นอยู่กับการดำเนินการก่อนหน้านี้และการกำหนดเวลาจะได้รับการจัดการเพื่อให้การดำเนินการทั้งหมดเสร็จสิ้นก่อนที่การดำเนินการครั้งสุดท้ายจะเสร็จสิ้น
Brad Larson

101

GCDเป็น C-based API ระดับต่ำ
NSOperationและNSOperationQueueเป็นคลาส Objective-C
NSOperationQueueเป็นวัตถุประสงค์ C GCDเสื้อคลุมมากกว่า หากคุณใช้ NSOperation แสดงว่าคุณใช้Grand Central Dispatchโดยปริยาย

ประโยชน์ GCD กว่า NSOperation:
ฉัน การดำเนินการ
สำหรับGCDการดำเนินงานเป็นอย่างมากน้ำหนักเบา
NSOperationQueueมีความซับซ้อนและน้ำหนักหนัก

ข้อได้เปรียบของ NSOperation เหนือ GCD:

ผม. ควบคุมการทำงานที่
คุณสามารถหยุดชั่วคราวยกเลิกดำเนินการต่อNSOperation

ii การพึ่งพา
คุณสามารถตั้งค่าการพึ่งพาระหว่างสองNSOperations
การดำเนินการจะไม่เริ่มจนกว่าการอ้างอิงทั้งหมดจะคืนค่าจริงเมื่อเสร็จสิ้น

สาม. สถานะของการดำเนินการ
สามารถตรวจสอบสถานะของการดำเนินการหรือคิวการดำเนินการ พร้อมดำเนินการหรือเสร็จสิ้น

iv จำนวนการดำเนิน
การสูงสุดคุณสามารถระบุจำนวนสูงสุดของการดำเนินการเข้าคิวที่สามารถทำงานพร้อมกันได้

ใช้เมื่อไรGCDหรือNSOperation
เมื่อคุณต้องการควบคุมการใช้คิว (ทั้งหมดที่กล่าวถึงข้างต้น) NSOperation และสำหรับกรณีง่าย ๆ ที่คุณต้องการค่าใช้จ่ายน้อยลง (คุณแค่ต้องการทำงานบางอย่างGCD

อ้างอิง:
https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html http : //nshipster.com/nsoperation/


ตามที่ได้กล่าวไปแล้วจำนวนสูงสุดของการดำเนินการสามารถระบุได้ใน NSOperationQueue แล้วจำนวนสูงสุดของการดำเนินการ (ส่งคิว) ใน GCD คืออะไร สมมติว่าฉันมีโครงการจากนั้นฉันจะสามารถดำเนินการกี่อย่าง (ส่งคิว) หรือเป็นข้อ จำกัด สูงสุดที่เราสามารถทำได้
Roshan Sah

มันขึ้นอยู่กับเงื่อนไขของระบบที่นี่คือข้อมูลรายละเอียด: stackoverflow.com/questions/14995801/ …
Sangram Shivankar

เราสามารถยกเลิกงานใน GCD ได้เช่นกันโดยใช้ DispatchWorkItem และเราสามารถระงับและทำงานต่อได้
Ankit garg

@Ankitgarg การโทรยกเลิกบน DispatchWorkItem จะหยุดภารกิจไม่ให้ทำงานหากยังไม่ได้ทำงาน แต่จะไม่หยุดสิ่งที่กำลังดำเนินการอยู่ และคุณจะหยุด / ทำงาน DispatchWorkItem ต่อได้อย่างไร?
abhimuralidharan

34

อีกเหตุผลที่ชอบ NSOperation มากกว่า GCD คือกลไกการยกเลิก NSOperation ตัวอย่างเช่นแอปเช่น 500px ที่แสดงภาพถ่ายนับสิบใช้ NSOperation เราสามารถยกเลิกการร้องขอของเซลล์รูปภาพที่มองไม่เห็นเมื่อเราเลื่อนมุมมองตารางหรือมุมมองคอลเลกชันซึ่งสามารถปรับปรุงประสิทธิภาพของแอปและลดการใช้หน่วยความจำ GCD ไม่สามารถรองรับสิ่งนี้ได้อย่างง่ายดาย

นอกจากนี้ด้วย NSOperation ทำให้สามารถใช้ KVO ได้

นี่คือบทความจาก Eschaton ซึ่งมีมูลค่าการอ่าน


4
เป็นที่น่าสังเกตว่าหากสิ่งที่คุณยกเลิกคือการดำเนินการเครือข่ายของการโหลดภาพจากนั้นคุณไม่จำเป็นต้องNSOperationใช้สิ่งนี้ NSURLSessionTask.cancelและNSURLSession.invalidateAndCancelให้ฟังก์ชั่นนี้ โดยทั่วไปแล้วNSURLSessionจะมีฟังก์ชั่นการใช้NSOperationQueueงานNSURLSessionTaskบางอย่างเช่นให้การทำงานบางอย่างของNSOperation
algal

@algal ตามที่อธิบายไว้ที่นี่ ( stackoverflow.com/questions/21918722/ … ) ดูเหมือนว่า NSURLSession ใช้ NSOperationQueue เป็นแบบเอกสารสำเร็จรูป
kanan nawarathne

33

GCD เป็นระดับที่ต่ำกว่า NSOperationQueue ข้อได้เปรียบที่สำคัญคือการใช้งานนั้นมีน้ำหนักเบามากและมุ่งเน้นไปที่อัลกอริธึมและประสิทธิภาพที่ไม่ล็อค

NSOperationQueue ให้บริการสิ่งอำนวยความสะดวกที่ไม่พร้อมใช้งานใน GCD แต่มีค่าใช้จ่ายที่ไม่สำคัญการดำเนินการของ NSOperationQueue นั้นซับซ้อนและมีน้ำหนักมากเกี่ยวข้องกับการล็อคจำนวนมากและใช้ GCD ภายในเพียงเล็กน้อยเท่านั้น

หากคุณต้องการสิ่งอำนวยความสะดวกที่ NSOperationQueue ให้ไว้ให้ใช้ แต่ถ้า GCD เพียงพอสำหรับความต้องการของคุณฉันขอแนะนำให้ใช้โดยตรงเพื่อประสิทธิภาพที่ดีขึ้นลดค่าใช้จ่าย CPU และพลังงานลงอย่างมากและมีความยืดหยุ่นมากขึ้น


24

ทั้ง NSQueueOperations และ GCD อนุญาตให้เรียกใช้งานการคำนวณอย่างหนักในพื้นหลังบนเธรดแยกกันโดยการเพิ่ม UI ของแอปพลิเคชันหลัก

ตามโพสต์ก่อนหน้านี้เราเห็นว่า NSOperations มี addDependency เพื่อให้คุณสามารถจัดคิวการทำงานของคุณทีละรายการตามลำดับ

แต่ฉันยังอ่านเกี่ยวกับคิวอนุกรม GCD ที่คุณสามารถสร้างการทำงานของคุณในคิวโดยใช้ dispatch_queue_create สิ่งนี้จะอนุญาตให้เรียกใช้ชุดการดำเนินการทีละรายการในลำดับ

ข้อดีของ NSQueueOperation เหนือ GCD:

  1. อนุญาตให้เพิ่มการพึ่งพาและอนุญาตให้คุณลบการพึ่งพาดังนั้นสำหรับธุรกรรมหนึ่งที่คุณสามารถเรียกใช้การเรียงลำดับโดยใช้การพึ่งพาและสำหรับธุรกรรมอื่น ๆ ที่ทำงานพร้อมกันในขณะที่ GCD ไม่อนุญาตให้ใช้วิธีนี้

  2. มันง่ายต่อการยกเลิกการดำเนินการหากอยู่ในคิวสามารถหยุดได้หากกำลังทำงานอยู่

  3. คุณสามารถกำหนดจำนวนสูงสุดของการดำเนินการพร้อมกัน

  4. คุณสามารถระงับการทำงานที่อยู่ในคิวได้

  5. คุณสามารถค้นหาจำนวนการดำเนินการที่รอดำเนินการอยู่ในคิว


6

GCD นั้นใช้งานง่ายมาก - ถ้าคุณต้องการทำอะไรบางอย่างในพื้นหลังสิ่งที่คุณต้องทำคือเขียนโค้ดและส่งไปยังคิวเบื้องหลัง การทำสิ่งเดียวกันกับ NSOperation นั้นเป็นงานที่เพิ่มขึ้นมากมาย

ข้อดีของ NSOperation คือ (a) คุณมีวัตถุจริงที่คุณสามารถส่งข้อความถึงและ (b) ที่คุณสามารถยกเลิก NSOperation นั่นไม่ใช่เรื่องเล็กน้อย คุณต้อง subclass NSOperation คุณต้องเขียนโค้ดของคุณอย่างถูกต้องเพื่อให้การยกเลิกและการทำภารกิจให้เสร็จถูกต้องทั้งคู่ทำงานอย่างถูกต้อง ดังนั้นสำหรับสิ่งง่ายๆที่คุณใช้ GCD และสำหรับสิ่งที่ซับซ้อนกว่านั้นคุณจะสร้างคลาสย่อยของ NSOperation (มีคลาสย่อย NSInvocationOperation และ NSBlockOperation แต่ทุกสิ่งที่พวกเขาทำทำได้ง่ายกว่าด้วย GCD ดังนั้นจึงไม่มีเหตุผลที่ดีที่จะใช้พวกเขา)


3

NSOperations เป็นเพียง API ที่สร้างขึ้นจาก Grand Central Dispatch ดังนั้นเมื่อคุณใช้ NSOperations คุณยังคงใช้ Grand Central Dispatch อยู่ มันเป็นเพียงแค่การที่ NSOperations มอบคุณสมบัติแฟนซีที่คุณอาจชอบ คุณสามารถทำให้การดำเนินงานบางอย่างขึ้นอยู่กับการดำเนินงานอื่น ๆ จัดลำดับคิวหลังจากที่คุณรายการรายการและสิ่งอื่น ๆ เช่น อันที่จริงแล้ว ImageGrabber กำลังใช้ NSOperations และคิวการดำเนินการอยู่แล้ว! ASIHTTPRequest ใช้มันภายใต้ประทุนและคุณสามารถกำหนดค่าคิวการดำเนินการที่ใช้สำหรับพฤติกรรมที่แตกต่างได้หากคุณต้องการ คุณควรใช้แบบไหนดี? แล้วแต่ความเหมาะสมสำหรับแอปของคุณ สำหรับแอพนี้มันค่อนข้างง่ายเราจึงใช้ Grand Central Dispatch โดยตรงไม่จำเป็นต้องใช้ฟีเจอร์แฟนซีของ NSOperation แต่ถ้าคุณต้องการแอพของคุณก็สามารถใช้งานได้ฟรี!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.