सवाल NSOperation और NSOperationQueue काम धागा बनाम मुख्य धागा


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

यह एप्लिकेशन परिदृश्य है:

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

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

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


76
2017-10-24 14:49


मूल


यदि आप मुख्य कतार में संचालन जोड़ते हैं, तो वे मुख्य धागे में किए जाएंगे। यदि आप अपना स्वयं का NSOperationQueue बनाते हैं और इसमें ऑपरेशन जोड़ते हैं, तो वे इस कतार के धागे में किए जाएंगे। - Cy-4AH
मुझे नहीं लगता कि आपको @ Cy-4AH की तुलना में बेहतर उत्तर प्राप्त करने जा रहे हैं जब तक कि आप कुछ विशिष्ट / कुछ कोड पोस्ट न करें। मैं कहूंगा कि आप हमेशा कोड में ब्रेकपॉइंट डाल सकते हैं और जब यह यात्रा करता है तो यह आपको दिखाएगा कि ट्रेस किस धागे में है। - Brad Allred
"एनएसओपरेशन के प्रतिनिधि को डेटा प्राप्त होगा।" क्या मतलब है? न NSOperation न NSOperationQueue प्रतिनिधि गुण शामिल हैं। - Jeffery Thomas
आप वर्तमान धागे के बारे में कोई धारणा करने के बजाय अपने प्रतिनिधि कॉल को मुख्य धागे पर भी धक्का दे सकते हैं ... - Wain


जवाब:


मेरा सवाल यह है कि डेटाबेस लेखन ऑपरेशन मुख्य में होता है या नहीं   धागा या पृष्ठभूमि धागे में?

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

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

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

ऑपरेशन कतार आमतौर पर उनके चलाने के लिए प्रयुक्त धागे प्रदान करते हैं   संचालन। ओएस एक्स 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 संचालन के लिए संदर्भ, पाया जा सकता है यहाँ। लेकिन संक्षेप में चक्र बनाए रखने से बचने के लिए है।


164
2017-11-02 21:07



जवाब सही है लेकिन कृपया ध्यान दें कि कोड की सही पंक्ति है: NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; और मुख्य धागे पर NSOperationQueue निलंबित नहीं किया जा सकता है। - Gianluca P.
@ जैकी-बॉय ब्याज से, डाउनलोड कोड के कमजोर संदर्भों का उपयोग क्यों करें और अंतिम कोड स्निपेट में सहेजेंडेटाबेसबेसऑपरेशन? - Michael Waterfall
रुईएपेरेस, अरे, मैं उत्सुक हूं कि अंतिम कोड स्निपेट में कमजोर संदर्भ क्यों उपयोग किए जा रहे हैं? क्या आप उस पर कुछ प्रकाश डाल सकते हैं? - Pavan
@ पवन विचार यह है कि यदि आप अपने ब्लॉक के अंदर एक ही ब्लॉक ऑपरेशन को संदर्भित करते हैं, तो आपको एक सतत चक्र मिल गया है। सन्दर्भ के लिए: conradstoll.com/blog/2013/1/19/... - Peres
तो कौन सा ब्लॉक उस ब्लॉक के समान है जो इसके अंदर चलता है? - Pavan


यदि आप पृष्ठभूमि थ्रेड में डेटाबेस लेखन ऑपरेशन करना चाहते हैं तो आपको एक बनाना होगा NSManagedObjectContext उस धागे के लिए।

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

के लिए ऐप्पल दस्तावेज़ों की जांच करें कोर डेटा के साथ Concurrency।

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


16
2017-10-30 09:31



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


से NSOperationQueue

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

इसलिए,

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

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


9
2017-11-01 13:32



बहुत बहुत धन्यवाद ... आप मेरी जिंदगी बचाओ: [NSOperationQueue new] // पोस्ट-आईओएस 4, मुख्य धागा नहीं होने की गारंटी है - ikanimo


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

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

यह सब मानते हैं कि आपने आगे कोई थ्रेडिंग नहीं किया है main उसकि विधि NSOperation जो वास्तविक राक्षस है जहां आपके पास कार्य निर्देश हैं (होने की उम्मीद है)।

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

संपादित करें -

मैंने आपका प्रश्न दिलचस्प पाया और कुछ विश्लेषण / खुद को लॉगिंग किया। मेरे पास इस तरह के मुख्य धागे पर बनाया गया 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]);

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

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


9
2017-10-30 05:07



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


दस्तावेज़ों का सारांश है operations are always executed on a separate thread (आईओएस 4 के बाद जीसीडी अंतर्निहित ऑपरेशन कतार का तात्पर्य है)।

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

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

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

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

1
2017-11-02 19:52





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


-2
2017-10-30 02:10



प्रश्न में एक विशिष्ट डेटाबेस का उल्लेख नहीं है, जैसे fmdb या sqlite। - Nikolai Ruhe
यह सही है, मैंने संदर्भ के आधार पर एक धारणा बनाई है। यदि ऐप एक बहु-किरायेदार, थ्रेड-सुरक्षित डेटाबेस, जैसे MySQL से कनेक्ट हो रहा था, तो सवाल समझ में नहीं आता है। ऐसे अन्य एकल-उपयोगकर्ता डेटाबेस हैं जिनका उपयोग किया जा सकता है, लेकिन SQLite अब तक का सबसे आम है। - Holly