Soru NSOperation ve NSOperationQueue iş parçacığı ana iş parçacığı vs


Uygulamamda bir dizi indirme ve veritabanı yazma işlemi yürütmem gerekiyor. Kullanıyorum NSOperation ve NSOperationQueue aynısı için.

Bu uygulama senaryosudur:

  • Tüm posta kodlarını bir yerden getir.
  • Her posta kodu için tüm evleri getir.
  • Her ev için sakinlik ayrıntıları

Dediğim gibi, NSOperation her görev için. İlk durumda (Görev1), tüm posta kodlarını almak için sunucuya bir istek gönderiyorum. İçindeki delege NSOperation veri alacaksınız. Bu veriler daha sonra veri tabanına yazılır. Veritabanı işlemi farklı bir sınıfta tanımlanmıştır. itibaren NSOperation sınıf veritabanı sınıfında tanımlanan yazma işlevine çağrı yapıyorum.

Sorum şu: veritabanı yazma işlemi ana iş parçacığında mı yoksa arka plan iş parçacığında mı gerçekleşiyor? Onu bir NSOperation Farklı bir iş parçacığı (Not MainThread) olarak çalıştırmak için bekliyordum. NSOperation. Birisi uğraşırken bu senaryoyu açıklayabilir mi NSOperation ve NSOperationQueue.


76
2017-10-24 14:49


Menşei


Ana sıraya işlem eklerseniz, ana iş parçacığında gerçekleştirilir. Kendi NSOperationQueue'nizi oluşturup ona işlem eklerseniz, bunlar bu sıradaki iş parçacıklarında gerçekleştirilir. - Cy-4AH
Ben daha spesifik olsun / kod göndermek sürece @ Cy-4AH verdi daha iyi bir cevap almak için gideceğini sanmıyorum. Kodda her zaman bir kırılma noktası koyabileceğinizi ve ne zaman gezindiğini söyleyeceğim, izlemenin hangi iş parçacığının içinde olduğunu gösterecektir. - Brad Allred
"NSOperation içindeki temsilci verileri alır." anlamına gelmek? ne NSOperation ne de NSOperationQueue temsilci özellikleri içerir. - Jeffery Thomas
Aynı zamanda delege çağrınızı mevcut iş parçacığı hakkında herhangi bir varsayım yapmak yerine ana iş parçacığına da aktarabilirsiniz ... - Wain


Cevaplar:


Sorum şu: veritabanı yazma işleminin ana bilgisayarda gerçekleşip gerçekleşmediği   iş parçacığı veya arka plan iş parçacığında?

Eğer bir NSOperationQueue sıfırdan itibaren:

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

Bir arka plan iş parçacığında olacak:

İşlem sıraları genellikle,   operasyonlar. OS X v10.6 ve sonraki sürümlerinde, işlem sıraları kullanılır.   başlatmak için libdispatch kütüphanesi (Grand Central Dispatch olarak da bilinir)   operasyonlarının yürütülmesi. Sonuç olarak, operasyonlar her zaman   ayrı bir iş parçacığı üzerinde yürütülürolup olmadıklarına bakılmaksızın   eşzamanlı veya eşzamanlı olmayan işlemler olarak atanmış

Kullanmadığınız sürece mainQueue:

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

Ayrıca şu kodu da görebilirsiniz:

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

   // Background work

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

Ve GCD sürümü:

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 Ne yapmak istediğiniz ile daha iyi kontrol sağlar. İki işlem arasında bağımlılıklar oluşturabilirsiniz (indirme ve veritabanına kaydetme). Verileri bir blok ile diğeri arasında iletmek için, örneğin NSData sunucudan geliyor olacak:

__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];

Düzenle: Neden kullanıyorum __weak Operasyonlar için referans, bulunabilir İşte. Ama kısaca döngüleri korumaktan kaçınmaktır.


164
2017-11-02 21:07



Cevap doğru ama lütfen doğru kod satırının olduğunu unutmayın: NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; ve ana iş parçacığı üzerinde NSOperationQueue askıya alınamaz. - Gianluca P.
@ jacky-boy Sonuçta, neden son kod parçacığında downloadOperation ve saveToDataBaseOperation zayıf referansların kullanımı? - Michael Waterfall
RuiAAPeres, hey son kod snippet'inde neden zayıf referansların kullanıldığını merak ediyorum. Biraz ışık tutabilir misin lütfen? - Pavan
@Pavan bu fikir, eğer kendi blok içinde aynı blok işlemine başvurursanız, bir tutma döngüsüne sahip olmanızdır. Referans için: conradstoll.com/blog/2013/1/19/... - Peres
hangi blok içinde çalışan blok ile aynıdır? - Pavan


Veritabanı yazma işlemini arka plan iş parçacığında gerçekleştirmek istiyorsanız, bir NSManagedObjectContext Bu konu için.

Arka plan oluşturabilirsiniz NSManagedObjectContext ilgili başlangıç ​​yönteminde NSOperation alt sınıf.

İçin Apple belgelerini kontrol edin. Çekirdek Verilerle Eşzamanlılık.

Ayrıca bir NSManagedObjectContext Bu, istekleri kendi arka plan iş parçacığıyla oluşturarak NSPrivateQueueConcurrencyType ve isteklerini kendi içinde gerçekleştirme performBlock: yöntem.


16
2017-10-30 09:31



Bu sorunun Çekirdek Veriler ile ilgili olduğunu düşünmenizi sağlayan nedir? - Nikolai Ruhe


itibaren NSOperationQueue

İOS 4 ve sonraki sürümlerde, işlem sıraları, işlemleri yürütmek için Grand Central Dispatch'u kullanır. İOS 4'ten önce, eşzamanlı olmayan işlemler için ayrı iş parçacıkları oluştururlar ve mevcut iş parçacığından eşzamanlı işlemleri başlatırlar.

Yani,

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

Durumunuzda, alt sınıflara göre kendi "veritabanı iş parçacığı" nı oluşturmak isteyebilirsiniz. NSThread ve ona mesaj gönderin performSelector:onThread:.


9
2017-11-01 13:32



çok teşekkürler ... hayatımı kurtarırım: [NSOperationQueue new] // iOS4 sonrası, ana iş parçacığı olmayı garantilemek - ikanimo


NSOperation yürütme iş parçacığına bağlıdır. NSOperationQueue operasyonu nereye eklediniz. Kodunuzdaki bu ifadeye bakın -

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

Tüm bunlar, daha fazla iş parçacığı yapmadığınızı varsayar. main yöntem NSOperation Yazdığınız iş talimatlarının (beklenen) gerçek canavarıdır.

Ancak, eşzamanlı operasyonlar durumunda, senaryo farklıdır. Sıra, her eş zamanlı işlem için bir iplik üretebilir. Her ne kadar guvenlikli olmasina ve sistem kaynaklari ile isletme kaynak taleplerine baglidir. bu noktada Sistemde. Operasyon kuyruğunun eşzamanlılığını kontrol edebilirsiniz. maxConcurrentOperationCount özelliği.

DÜZENLE -

Sorunuzu ilginç buldum ve bazı analizler / kayıtlar yaptım. NSOperationQueue gibi ana iş parçacığı üzerinde oluşturdum -

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

Ve sonra, bir NSOperation oluşturmak için devam ettim ve addOperation kullanarak ekledim. Şu anki iş parçacığı için kontrol ettiğimde bu işlemin ana yönteminde,

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

Ana iş parçacığı değildi. Ve, mevcut iş parçacığının ana iş parçacığı olmadığını buldum.

Bu nedenle, ana iş parçacığı üzerinde sıraya özel olarak oluşturma (işlemi arasında eşzamanlılık olmadan), işlemlerin ana iş parçacığı üzerinde seri olarak yürütüleceği anlamına gelmez.


9
2017-10-30 05:07



Ben inanıyorum [[NSOperationQueue alloc] init] sıraya, temel bir varsayılan arka plan genel DispatchQueue kullanacaktır. Böylece herhangi bir özel başlatılmış OperationQueue görevlerini DispatchQueues arka planına besleyecek ve bu nedenle görevleri ana iş parçacığı olmayan iş parçacıklarına besleyecektir. İşlemleri ana iş parçacığına beslemek için, ana OperationQueue gibi bir şey kullanarak [NSOperationQueue mainQueue]. Bu, ana DispatchQueue'yu dahili olarak kullanan ana işlem sırasını alır ve bu nedenle görevleri ana iş parçacığına besler. - Gordonium


Dokümanlar özetidir operations are always executed on a separate thread (iOS 4 sonrası GCD temelindeki işlem sıralarını ifade eder).

Gerçekten ana olmayan bir iş parçacığında çalıştığını kontrol etmek çok önemlidir:

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

Bir iş parçacığı çalışırken, ana iş parçacığı, ana veri, kullanıcı arabirimi veya ana iş parçacığı üzerinde çalıştırmak için gereken diğer kod üzerinde bir şey çalıştırmak için GCD / libdispatch kullanmak için önemsiz:

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

1
2017-11-02 19:52





Önemsiz bir iş parçacığı yapıyorsanız, kullanmalısınız FMDatabaseQueue.


-2
2017-10-30 02:10



Soru, fmdb veya sqlite gibi belirli bir veritabanından bahsetmiyor. - Nikolai Ruhe
Bu doğru, içeriğe dayalı bir varsayım yaptım. Uygulama, MySQL gibi çok kullanıcılı, iş parçacığı güvenli bir veritabanına bağlanıyorsa, bu soru mantıklı olmaz. Kullanılabilecek diğer tek kullanıcı veritabanları vardır, ancak SQLite en yaygın olanıdır. - Holly