SORU
30 HAZİRAN 2011, PERŞEMBE


dispatch_sync vs dispatch_async ana sıra

Benimle ayı, bu açıklaması kolay oluyor. Bir aşağıdaki gibi görünen bir işlevi var.

İçerik: "bir dizi 'memberFiles' başka bir Temel Veri varlık LPFile adlı örneklerini içeriyor. adında" Temel Veri bir varlık LPProject adlı aProject Her LPFile disk üzerinde bir dosyayı temsil eder ve yapmak istediğimiz şey, bu dosyaların her biri, açık ve metin ayrıştırma, @DİĞER dosya üzerine gelin ifadelerini almak için arıyor. Eğer bulabilirsem @import deyimleri, istediğimiz bulun dosyayı işaret etmek ve sonra 'link' bu dosya için bu ekleyerek bir ilişkinin temel veri varlık gösteren ilk dosya. Bütün bunlar büyük dosyalar üzerinde biraz zaman alabilir bu yana, ana iş parçacığı kullanarak GCD kapalı yaparız.

- (void) establishImportLinksForFilesInProject:(LPProject *)aProject {
    dispatch_queue_t taskQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     for (LPFile *fileToCheck in aProject.memberFiles) {
         if (//Some condition is met) {
            dispatch_async(taskQ, ^{
                // Here, we do the scanning for @import statements. 
                // When we find a valid one, we put the whole path to the imported file into an array called 'verifiedImports'. 

                // go back to the main thread and update the model (Core Data is not thread-safe.)
                dispatch_sync(dispatch_get_main_queue(), ^{

                    NSLog(@"Got to main thread.");

                    for (NSString *import in verifiedImports) {  
                            // Add the relationship to Core Data LPFile entity.
                    }
                });//end block
            });//end block
        }
    }
}

Şimdi, burada işler garipleşiyor nerede:

Bu kod çalışıyor ama tek bir sorun görüyorum. Ben bir kaç dosya (20) olan bir LPProject üzerinde çalıştırmak, mükemmel bir şekilde çalışır. Ben daha çok dosya olan bir LPProject üzerinde çalıştırmak ancak, 60-70 ki), yokDEĞİLdoğru çalıştırın. Biz asla geri ana konuya gir, NSLog(@"got to main thread"); asla görünür ve uygulama kilitleniyor. Ve bu GERÇEKTEN garip şeyler oluyor) AMA --- küçük proje kodu İLK ben çalıştırmak ve büyük proje üzerinde çalıştırın, her şey mükemmel çalışıyor. Sorun gösterir büyük proje kodu ilk ben yönetiyorum SADECE.

Ve burada eğer bu satır gönderme değiştirirsem atışı,:

dispatch_async(dispatch_get_main_queue(), ^{

(async yerine sync ana sıraya blok göndermek için kullanın), her şey her zaman çalışır. Mükemmel. Proje dosyalarında sayısı ne olursa olsun!

Bir kayıp bu davranışını açıklamak için geldim. Bir sonraki test için ne herhangi bir yardım veya ipuçları mutluluk duyacağız.

CEVAP
1 Temmuz 2011, Cuma


Bu ortak bir sorun, disk I/O ve GCD ile ilgilidir. Temelde, GCD muhtemelen her dosya için bir iş parçacığı yumurtlama ve belli bir noktada makul bir süre içinde hizmete sistemi için çok fazla konu var.

Her zaman dediğiniz dispatch_async() ve bu blok girişimi için herhangi bir I/O (örneğin, göründüğü gibi okuyorsun bazı dosyaları burada), muhtemelen bu konuya olan blok kod yürütülmesini engeller (duraklatıldı tarafından OS) süre bekler verileri okumaya gelen dosya. Yol GCD çalışır gibi yaparken gördüğü bir çalışan iş parçacığı bloke I/O ve sen hala bunu sormak için daha fazla işi aynı anda, sadece spawn yeni bir iş parçacığı. Böylece eğer eşzamanlı bir sıra 50 dosya açmaya çalışırsanız, GCD ~50 iş parçacığı spawn neden olacak olman muhtemel.

Bu sistemi anlamlı bir şekilde hizmet etmek için çok fazla iş parçacığı ve CPU için ana Konu aç.

Bunu düzeltmenin bir yolunu dosya tabanlı işlemleri yapmak için eşzamanlı bir sıra yerine seri sıra kullanmaktır. Bunu yapmak çok kolay. Birden fazla seri kuyruklar oluştururken sonunda yok bu yüzden seri bir sıra oluşturalım ve nesne bir ıvar olarak saklayın. Bu aramayı Kaldır:

dispatch_queue_t taskQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Init yöntemi: bu ekleyin

taskQ = dispatch_queue_create("com.yourcompany.yourMeaningfulLabel", DISPATCH_QUEUE_SERIAL);

Dealloc yöntemi: bu ekleyin

dispatch_release(taskQ);

Ve sınıf bildirimi içinde bir ıvar olarak bu ekleyin:

dispatch_queue_t taskQ;

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • booba1234

    booba1234

    22 Temmuz 2006
  • Maschine Tutorials

    Maschine Tut

    15 ŞUBAT 2011
  • stewmurray47

    stewmurray47

    1 Kasım 2006