ทำความเข้าใจกับ dispatch_async


233

ฉันมีคำถามเกี่ยวกับรหัสนี้

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData* data = [NSData dataWithContentsOfURL: 
      kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:) 
      withObject:data waitUntilDone:YES];
});

พารามิเตอร์แรกของรหัสนี้คือ

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

เรากำลังขอรหัสนี้เพื่อทำงานแบบอนุกรมในคิวทั่วโลกที่มีความหมายว่ามันจะส่งกลับพร้อมกันทั่วโลกคิวในระดับความสำคัญที่กำหนด?

อะไรคือข้อดีของการใช้dispatch_get_global_queueคิวหลัก?

ฉันสับสน. คุณช่วยฉันเข้าใจเรื่องนี้ให้ดีขึ้นได้ไหม


1
คุณควรตัดโค้ดของคุณในหลายบรรทัดเพื่อให้เข้าใจได้ง่ายขึ้น ความปลอดภัยของคุณภายในประเภทของตัวแปรdispatch_get_global_queue dispatch_queue_t myQueueมันอ่านได้มากขึ้นเท่านั้นผ่านmyQueueของคุณเพื่อ `` dispatch_async '
อเล็กซ์ Cio

คำตอบ:


517

เหตุผลหลักที่คุณใช้คิวเริ่มต้นเหนือคิวหลักคือการทำงานในพื้นหลัง

ตัวอย่างเช่นหากฉันกำลังดาวน์โหลดไฟล์จากอินเทอร์เน็ตและฉันต้องการอัพเดตผู้ใช้เกี่ยวกับความคืบหน้าของการดาวน์โหลดฉันจะเรียกใช้การดาวน์โหลดในลำดับความสำคัญเริ่มต้นของคิวและอัปเดต UI ในคิวหลักแบบอะซิงโครนัส

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});

ฉันเข้าใจว่า david ขอบคุณสำหรับคำตอบของคุณว่า แต่คำถามของฉันมีมากกว่าที่จะเข้าใจตรรกะของการทำเช่นนี้คือการขอให้รหัสนี้ดำเนินงานอนุกรมในคิวทั่วโลกซึ่งเป็นคิวพร้อมกันเอง
user2332873

ฉันกำลังทำสิ่งที่คุณแนะนำ แต่อย่างใด uiTableViewCell ไม่อัปเดตทันทีเมื่อฉันเรียก [self.tableView reloadData] ใน Run UI Updates ใช้เวลาประมาณ 4 หรือ 5 วินาทีมันทำให้ฉันคลั่งไปหลายวันแล้ว .
GrandSteph

@GrandSteph ฉันไม่คุ้นเคยกับวิธีการนั้นมากเกินไป บางทีวิธีการนั้นอาจใช้เวลา 5 วินาทีในการทำงาน สิ่งสำคัญกับ dispatch_async คือมันช่วยให้คุณทำสิ่งต่าง ๆ ในพื้นหลังโดยไม่ต้องแขวนเธรดหลัก
David

2
สิ่งที่0มีความหมาย?
ฮันนี่

3
@Honey 0 เป็นflagsพารามิเตอร์ซึ่งปัจจุบันไม่ทำอะไรเลยอย่างแน่นอน จากเอกสาร:Flags that are reserved for future use. Always specify 0 for this parameter.
เดวิด

199

DISPATCH_QUEUE_PRIORITY_X ทั้งหมดเป็นคิวที่เกิดขึ้นพร้อมกัน (หมายถึงพวกเขาสามารถทำงานหลายอย่างพร้อมกัน) และเป็น FIFO ในแง่ที่ว่างานภายในคิวที่กำหนดจะเริ่มดำเนินการโดยใช้คำสั่ง "เข้าก่อนออกก่อน" นี่เป็นการเปรียบเทียบกับคิวหลัก (จาก dispatch_get_main_queue ()) ซึ่งเป็นลำดับคิว (งานจะเริ่มดำเนินการและสิ้นสุดการดำเนินการตามลำดับที่ได้รับ)

ดังนั้นถ้าคุณส่งบล็อค 1,000 dispatch_async () ไปที่ DISPATCH_QUEUE_PRIORITY_DEFAULT งานเหล่านั้นจะเริ่มดำเนินการตามลำดับที่คุณส่งไปยังคิว เช่นเดียวกันสำหรับคิว HIGH, LOW และ BACKGROUND ทุกสิ่งที่คุณส่งไปยังคิวใด ๆ เหล่านี้จะถูกดำเนินการในพื้นหลังของเธรดทางเลือกห่างจากเธรดแอปพลิเคชันหลักของคุณ ดังนั้นคิวเหล่านี้จึงเหมาะสำหรับการดำเนินงานต่างๆเช่นการดาวน์โหลดพื้นหลังการบีบอัดการคำนวณ ฯลฯ

โปรดทราบว่าลำดับของการดำเนินการคือ FIFO บนพื้นฐานต่อคิว ดังนั้นถ้าคุณส่งงาน 1,000 dispatch_async () ไปยังสี่คิวที่ต่างกันพร้อมกันให้แบ่งพวกมันออกและส่งไปที่ BACKGROUND, LOW, DEFAULT และ HIGH ตามลำดับ (เช่นคุณจัดตารางงาน 250 ครั้งล่าสุดในคิว HIGH) งานแรกที่คุณเห็นการเริ่มต้นจะอยู่ในคิว HIGH นั้นเนื่องจากระบบได้ใช้ความหมายของคุณว่างานเหล่านั้นต้องไปถึง CPU โดยเร็วที่สุด

โปรดทราบด้วยว่าฉันจะพูดว่า "จะเริ่มดำเนินการตามลำดับ" แต่โปรดจำไว้ว่าเนื่องจากคิวต่างๆที่เกิดขึ้นพร้อมกันนั้นไม่จำเป็นว่า FINISH จะดำเนินการตามลำดับโดยขึ้นอยู่กับระยะเวลาสำหรับแต่ละงาน

ตามแอปเปิ้ล:

https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

คิวการจัดส่งพร้อมกันมีประโยชน์เมื่อคุณมีหลายงานที่สามารถทำงานแบบขนาน คิวที่เกิดขึ้นพร้อมกันยังคงเป็นคิวที่จะทำการถอนงานตามลำดับการเข้าก่อนออกก่อน อย่างไรก็ตามคิวที่เกิดขึ้นพร้อมกันอาจ dequeue งานเพิ่มเติมก่อนที่งานก่อนหน้านี้จะเสร็จสิ้น จำนวนงานจริงที่ดำเนินการโดยคิวที่เกิดขึ้นพร้อมกันในขณะใดก็ตามเป็นตัวแปรและสามารถเปลี่ยนแปลงแบบไดนามิกตามเงื่อนไขในการเปลี่ยนแปลงแอปพลิเคชันของคุณ มีหลายปัจจัยที่ส่งผลต่อจำนวนงานที่ดำเนินการโดยคิวที่เกิดขึ้นพร้อมกันรวมถึงจำนวนของคอร์ที่มีอยู่จำนวนของงานที่ทำโดยกระบวนการอื่น ๆ และจำนวนและลำดับความสำคัญของงานในคิวการจัดส่งอนุกรมอื่น ๆ

โดยทั่วไปถ้าคุณส่งบล็อค 1,000 dispatch_async () เหล่านั้นไปยังคิว DEFAULT, HIGH, LOW หรือ BACKGROUND พวกเขาทั้งหมดจะเริ่มดำเนินการตามลำดับที่คุณส่ง อย่างไรก็ตามงานที่สั้นลงอาจเสร็จสิ้นก่อนงานที่ยาวขึ้น เหตุผลที่อยู่เบื้องหลังคือหากมีคอร์ CPU อยู่หรือหากงานคิวปัจจุบันกำลังทำงานที่ไม่ต้องใช้คอมพิวเตอร์มาก (ทำให้ระบบคิดว่ามันสามารถส่งงานเพิ่มเติมในแบบคู่ขนานโดยไม่คำนึงถึงจำนวนหลัก)

ระดับของการทำงานพร้อมกันได้รับการจัดการโดยระบบทั้งหมดและขึ้นอยู่กับภาระของระบบและปัจจัยอื่น ๆ ที่กำหนดไว้ภายใน นี่คือความงามของระบบ Grand Central Dispatch (ระบบ dispatch_async ()) - คุณเพียงแค่ทำให้หน่วยงานของคุณเป็นบล็อคโค้ดตั้งค่าลำดับความสำคัญสำหรับพวกเขา (ตามคิวที่คุณเลือก) และให้ระบบจัดการส่วนที่เหลือ

ดังนั้นเพื่อตอบคำถามข้างต้นของคุณ: คุณถูกต้องบางส่วน คุณกำลัง "ถามรหัสนั้น" เพื่อทำงานพร้อมกันในคิวทั่วโลกพร้อมกันในระดับความสำคัญที่ระบุ รหัสในบล็อกจะดำเนินการในพื้นหลังและรหัสเพิ่มเติม (คล้ายกัน) ใด ๆ ที่จะดำเนินการอาจขนานกันขึ้นอยู่กับการประเมินของระบบของทรัพยากรที่มีอยู่

คิว "main" ในอีกทางหนึ่ง (จาก dispatch_get_main_queue ()) เป็นคิวอนุกรม (ไม่เกิดขึ้นพร้อมกัน) งานที่ส่งไปยังคิวหลักจะดำเนินการตามลำดับและจะเสร็จสิ้นตามลำดับ งานเหล่านี้จะถูกดำเนินการใน UI Thread ดังนั้นจึงเหมาะสำหรับการอัปเดต UI ของคุณด้วยข้อความความคืบหน้าการแจ้งเตือนความสำเร็จ ฯลฯ


+1 แต่ฉันคิดว่าในทางปฏิบัติมันไม่สำคัญว่าคิวที่เกิดขึ้นพร้อมกันนั้นเป็นแบบ FIFO หรือเพียงแค่สุ่มลำดับ หากคุณเริ่มงาน 5 ครั้งในลูปสมมติว่าพวกเขาจะเริ่มในเวลาเดียวกัน ไม่มีการรับประกันว่าเช่นการดำเนินงาน I / O ครั้งแรกของงานที่ 1 จะเกิดขึ้นก่อนวันที่ 5 แม้ว่าพวกเขาจะเรียกใช้รหัสเดียวกัน OTOH สำหรับอนุกรมคิวพฤติกรรม FIFO เป็นสิ่งสำคัญและ IMHO นี่คือความแตกต่างที่กำหนดระหว่างสองประเภทคิว
แกร์ฮาร์ดเวส

คำอธิบายที่น่าเหลือเชื่อ ตบมือมาก!
Okhan Okbay

36

รุ่นที่รวดเร็ว

นี่คือคำตอบ Objective-C รุ่น David ที่รวดเร็ว คุณใช้คิวส่วนกลางเพื่อเรียกใช้สิ่งต่าง ๆ ในพื้นหลังและคิวหลักเพื่อปรับปรุง UI

DispatchQueue.global(qos: .background).async {
    
    // Background Thread
    
    DispatchQueue.main.async {
        // Run UI Updates
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.