NSOperation और NSOperationQueue वर्किंग थ्रेड बनाम मुख्य थ्रेड


81

मुझे अपने ऐप में डाउनलोड और डेटाबेस राइट्स ऑपरेशंस की एक श्रृंखला लेनी है। मैं NSOperationऔर NSOperationQueueउसी के लिए उपयोग कर रहा हूं ।

यह अनुप्रयोग परिदृश्य है:

  • एक स्थान से सभी पोस्टकोड प्राप्त करें।
  • प्रत्येक पोस्टकोड के लिए सभी घरों को प्राप्त करें।
  • प्रत्येक घर के निवासियों के विवरण के लिए

जैसा कि कहा गया है, मैंने NSOperationप्रत्येक कार्य के लिए परिभाषित किया है । पहले मामले में (टास्क 1), मैं सभी पोस्टकोडों को लाने के लिए सर्वर से अनुरोध भेज रहा हूं। NSOperationवसीयत के भीतर प्रतिनिधि को डेटा प्राप्त होगा। यह डेटा तब डेटाबेस में लिखा जाता है। डेटाबेस ऑपरेशन को एक अलग वर्ग में परिभाषित किया गया है। से NSOperationकक्षा मैं लिखने समारोह डेटाबेस वर्ग में परिभाषित करने के लिए कोई कॉल करने से कर रहा हूँ।

मेरा सवाल यह है कि क्या डेटाबेस राइट ऑपरेशन मेन थ्रेड में या बैकग्राउंड थ्रेड में होता है? जैसा कि मैं इसे भीतर बुला NSOperationरहा था मैं उम्मीद कर रहा था कि यह एक अलग थ्रेड (नॉट मेनह्रेड) में चलने के लिए है NSOperation। क्या कोई इस परिदृश्य को समझा सकता है NSOperationऔर साथ काम करते समय NSOperationQueue


3
यदि आप ऑपरेशन को मुख्य कतार में जोड़ते हैं, तो वे मुख्य धागे में प्रदर्शन करेंगे। यदि आप अपना स्वयं का NSOperationQueue बनाते हैं और इसमें ऑपरेशन जोड़ते हैं, तो वे इस कतार के थ्रेड्स में प्रदर्शन करेंगे।
Cy-4AH

1
मुझे नहीं लगता कि आप @ Cy-4AH की तुलना में बेहतर जवाब पाने जा रहे हैं, जब तक कि आपको कुछ विशिष्ट / कुछ कोड प्राप्त न हों। मैं कहूंगा कि आप हमेशा कोड में एक ब्रेकपॉइंट डाल सकते हैं और जब यह यात्रा करता है तो यह आपको दिखाएगा कि ट्रेस किस धागे में है?
ब्रैड एलाड

क्या "NSOperation के भीतर प्रतिनिधि को डेटा प्राप्त होगा।" मतलब? न तो NSOperationऔर न ही NSOperationQueueप्रतिनिधि गुण होते हैं।
जेफ़री थॉमस

आप यह भी नहीं बल्कि वर्तमान धागा के बारे में कोई धारणा बनाने से मुख्य थ्रेड पर अपना प्रतिनिधि कॉल धक्का कर सकते हैं ...
वेन

जवाबों:


175

मेरा सवाल यह है कि क्या डेटाबेस राइट ऑपरेशन मेन थ्रेड में या बैकग्राउंड थ्रेड में होता है?

यदि आप NSOperationQueueस्क्रैच से बनाते हैं :

NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];

यह एक पृष्ठभूमि धागे में होगा:

ऑपरेशन कतारें आमतौर पर उनके संचालन को चलाने के लिए उपयोग किए जाने वाले धागे प्रदान करती हैं। OS X v10.6 में और बाद में, ऑपरेशन कतारें अपने कार्यों के निष्पादन को आरंभ करने के लिए libdispatch लाइब्रेरी (जिसे ग्रैंड सेंट्रल डिस्पैच भी कहा जाता है) का उपयोग करती हैं। परिणामस्वरूप, ऑपरेशन हमेशा एक अलग थ्रेड पर निष्पादित होते हैं , चाहे वे समवर्ती या गैर-समवर्ती संचालन के रूप में नामित किए गए हों

जब तक आप उपयोग नहीं कर रहे हैं mainQueue:

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

आप इस तरह कोड भी देख सकते हैं:

NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
[myQueue addOperationWithBlock:^{

   // Background work

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // Main thread work (UI usually)
    }];
}];

और जीसीडी संस्करण:

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
             {
              // Background work            
             dispatch_async(dispatch_get_main_queue(), ^(void)
              {
                   // Main thread work (UI usually)                          
              });
});

NSOperationQueueआप क्या करना चाहते हैं के साथ बेहतर नियंत्रण देता है। आप दो ऑपरेशनों के बीच निर्भरता बना सकते हैं (डाउनलोड करें और डेटाबेस में सहेजें)। एक ब्लॉक और दूसरे के बीच डेटा पास करने के लिए, आप उदाहरण के लिए मान सकते हैं, कि NSDataसर्वर से आ रहा होगा:

__block NSData *dataFromServer = nil;
NSBlockOperation *downloadOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakDownloadOperation = downloadOperation;

[weakDownloadOperation addExecutionBlock:^{
 // Download your stuff  
 // Finally put it on the right place: 
 dataFromServer = ....
 }];

NSBlockOperation *saveToDataBaseOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakSaveToDataBaseOperation = saveToDataBaseOperation;

 [weakSaveToDataBaseOperation addExecutionBlock:^{
 // Work with your NSData instance
 // Save your stuff
 }];

[saveToDataBaseOperation addDependency:downloadOperation];

[myQueue addOperation:saveToDataBaseOperation];
[myQueue addOperation:downloadOperation];

संपादित करें: मैं __weakसंचालन के लिए संदर्भ का उपयोग क्यों कर रहा हूं , यहां पाया जा सकता है । लेकिन संक्षेप में चक्र को बनाए रखने से बचना है।


3
उत्तर सही है, लेकिन कृपया ध्यान दें कि कोड की सही लाइन है: NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];और मुख्य धागे पर NSOperationQueue को निलंबित नहीं किया जा सकता है।
जियानलुका पी।

2
@ जैकी-बॉय आउट ऑफ इंटरेस्ट, डाउनलोड कोड में कमजोर संदर्भों का उपयोग क्यों करें और अंतिम कोड स्निपेट में SaveToDataBaseOperation?
माइकल वाटरफॉल

रुईऐपर्स, अरे मैं उत्सुक हूं कि अंतिम कोड स्निपेट में कमजोर संदर्भ क्यों इस्तेमाल किए जा रहे हैं? क्या आप उस पर कुछ प्रकाश डाल सकते हैं?
पावन

@ पावन विचार यह है कि यदि आप उसी ब्लॉक ऑपरेशन का संदर्भ अपने ही ब्लॉक के अंदर करते हैं, तो आपको रिटेन साइकिल मिल जाता है। संदर्भ के लिए: conradstoll.com/blog/2013/1/19/…
Rui Peres

तो कौन सा ब्लॉक उसके अंदर चलने वाले ब्लॉक के समान है?
पावन

16

यदि आप बैकग्राउंड थ्रेड में डेटाबेस राइटिंग ऑपरेशन करना चाहते हैं तो आपको NSManagedObjectContextउस थ्रेड के लिए बनाने की आवश्यकता है ।

आप NSManagedObjectContextअपने प्रासंगिक NSOperationउपवर्ग की शुरुआत विधि में पृष्ठभूमि बना सकते हैं ।

कोर डेटा के साथ कंसीडर के लिए Apple डॉक्स की जाँच करें

आप NSManagedObjectContextअपने स्वयं के पृष्ठभूमि थ्रेड में अनुरोधों को निष्पादित कर सकते हैं NSPrivateQueueConcurrencyTypeऔर इसे अपनी performBlock:विधि के अंदर अनुरोधों के साथ बना सकते हैं ।


17
आपको क्या लगता है कि यह प्रश्न कोर डेटा से संबंधित है?
निकोलाई रुहे

11

से NSOperationQueue

आईओएस 4 और बाद में, संचालन को निष्पादित करने के लिए ऑपरेशन कतार ग्रैंड सेंट्रल डिस्पैच का उपयोग करते हैं। IOS 4 से पहले, वे गैर-समवर्ती संचालन के लिए अलग थ्रेड बनाते हैं और वर्तमान थ्रेड से समवर्ती संचालन लॉन्च करते हैं।

इसलिए,

[NSOperationQueue mainQueue] // added operations execute on main thread
[NSOperationQueue new] // post-iOS4, guaranteed to be not the main thread

आपके मामले में, आप सबक्लास करके अपना "डेटाबेस थ्रेड" बनाना चाहते हैं NSThreadऔर इसके साथ संदेश भेज सकते हैं performSelector:onThread:


बहुत बहुत धन्यवाद ... u मेरी जान बचाओ: [NSOperationQueue new] // post-iOS4, मुख्य धागा नहीं होने की गारंटी
ikanimo

9

NSOperation का निष्पादन थ्रेड इस बात पर निर्भर करता है NSOperationQueueकि आपने ऑपरेशन को कहाँ जोड़ा है। इस कथन को अपने कोड में देखें -

[[NSOperationQueue mainQueue] addOperation:yourOperation]; // or any other similar add method of NSOperationQueue class

यह सब मान लिया जाता है कि आपने आगे कोई ऐसा mainतरीका नहीं अपनाया है, NSOperationजो वास्तविक राक्षस हो, जहाँ आपके पास काम के निर्देश (अपेक्षित हो) लिखा गया हो।

हालांकि, समवर्ती संचालन के मामले में, परिदृश्य अलग है। कतार प्रत्येक समवर्ती ऑपरेशन के लिए एक धागा पैदा कर सकती है। हालांकि यह ग्वारंटेड नहीं है और यह सिस्टम संसाधनों पर निर्भर करता है। सिस्टम में उस बिंदु पर ऑपरेशन संसाधन की मांग । आप maxConcurrentOperationCountसंपत्ति द्वारा ऑपरेशन कतार की संगणना को नियंत्रित कर सकते हैं।

EDIT -

मैंने आपके प्रश्न को दिलचस्प पाया और कुछ विश्लेषण / लॉगिंग स्वयं की। मैं इस तरह मुख्य धागे पर बनाया NSOperationQueue है -

self.queueSendMessageOperation = [[[NSOperationQueue alloc] init] autorelease];

NSLog(@"Operation queue creation. current thread = %@ \n main thread = %@", [NSThread currentThread], [NSThread mainThread]);
self.queueSendMessageOperation.maxConcurrentOperationCount = 1; // restrict concurrency

और फिर, मैंने एक NSOperation बनाया और AddOperation का उपयोग करके इसे जोड़ा। इस ऑपरेशन की मुख्य विधि में जब मैंने वर्तमान थ्रेड के लिए जाँच की,

NSLog(@"Operation obj =  %@\n current thread = %@ \n main thread = %@", self, [NSThread currentThread], [NSThread mainThread]);

यह मुख्य धागे के रूप में नहीं था। और, पाया गया कि वर्तमान थ्रेड ऑब्जेक्ट मुख्य थ्रेड ऑब्जेक्ट नहीं है।

तो, मुख्य धागे पर कतार का कस्टम निर्माण (इसके संचालन के बीच कोई संगामिति के साथ) जरूरी नहीं है कि ऑपरेशन अपने धागे पर क्रमिक रूप से निष्पादित होगा।


मेरा मानना ​​है [[NSOperationQueue alloc] init]कि यह विश्वास दिलाता हूं कि कतार एक अंतर्निहित डिफ़ॉल्ट पृष्ठभूमि ग्लोबल डिस्पैचक्यू का उपयोग करेगी। इसलिए किसी भी कस्टम इनिशियलाइज़्ड ऑपरेशन क्यू को अपने टास्क को बैकग्राउंड डिस्पैचक्यू पर फीड करेंगे और इसलिए थ्रेड्स में टास्क फीड करेंगे जो कि मुख्य धागा नहीं हैं। ऑपरेशन को मुख्य धागे में खिलाने के लिए आपको कुछ चीज़ों का उपयोग करके मुख्य OperationQueue प्राप्त करना होगा [NSOperationQueue mainQueue]। यह मुख्य ऑपरेशन कतार को प्राप्त करता है जो आंतरिक रूप से मुख्य डिस्पैचक्यू का उपयोग करता है और इसलिए अंततः मुख्य धागे पर कार्यों को खिलाता है।
गॉर्डनियम

1

डॉक्स से सारांश operations are always executed on a separate thread(पोस्ट iOS 4 का अर्थ है GCD अंतर्निहित ऑपरेशन कतार)।

यह जाँचना तुच्छ है कि यह वास्तव में एक गैर-मुख्य धागे पर चल रहा है:

NSLog(@"main thread? %@", [NSThread isMainThread] ? @"YES" : @"NO");

जब एक धागे में चल रहा है, तो मुख्य धागे पर कुछ चलाने के लिए जीसीडी / लिबिडस्पिच का उपयोग करना तुच्छ है, चाहे मुख्य डेटा, उपयोगकर्ता इंटरफ़ेस या अन्य कोड मुख्य धागे पर चलाने के लिए आवश्यक हो:

dispatch_async(dispatch_get_main_queue(), ^{
    // this is now running on the main thread
});

-2

यदि आप कोई गैर-तुच्छ थ्रेडिंग कर रहे हैं, तो आपको FMDatabaseQueue का उपयोग करना चाहिए ।


1
प्रश्न में किसी विशिष्ट डेटाबेस का उल्लेख नहीं है, जैसे fmdb या sqlite।
निकोलाई रुहे

यह सही है, मैंने संदर्भ के आधार पर एक धारणा बनाई। यदि ऐप एक बहु-किरायेदार, थ्रेड-सुरक्षित डेटाबेस, जैसे कि MySQL से कनेक्ट हो रहा था, तो सवाल समझ में नहीं आएगा। अन्य एकल-उपयोगकर्ता डेटाबेस हैं जिनका उपयोग किया जा सकता है, लेकिन SQLite अब तक सबसे आम है।
होली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.