Kann jemand mit wirklich klaren Anwendungsfällen erklären, wozu der Zweck von dispatch_sync
in GCD
dient? Ich kann nicht verstehen, wo und warum ich das verwenden müsste.
Vielen Dank!
cocoa
ios
ios4
grand-central-dispatch
Rasputin Jones
quelle
quelle
dispatch_async
gefolgt von einerdispatch_sync
in derselben Warteschlange. Das gleiche Muster ist jedoch nützlich, wenn Sie mehrere gleichzeitige Jobs in einer anderen Warteschlange erzeugen und dann auf alle warten möchten.-performSelector:onThread:withObject:waitUntilDone:
oder verwendenperformSelectorOnMainThread:withObject:waitUntilDone:
undwaitUntilDone
auf JA setzen.Verstehe zuerst seinen Bruder
dispatch_async
//Do something dispatch_async(queue, ^{ //Do something else }); //Do More Stuff
Sie verwenden
dispatch_async
, um einen neuen Thread zu erstellen. Wenn Sie dies tun, wird der aktuelle Thread nicht gestoppt. Das heißt,//Do More Stuff
kann vor dem//Do something else
Abschluss ausgeführt werdenWas passiert, wenn der aktuelle Thread gestoppt werden soll?
Sie verwenden den Versand überhaupt nicht. Schreiben Sie den Code einfach normal
//Do something //Do something else //Do More Stuff
Angenommen, Sie möchten etwas in einem VERSCHIEDENEN Thread tun und warten, als ob und stellen Sie sicher, dass die Dinge nacheinander ausgeführt werden .
Dafür gibt es viele Gründe. Die Aktualisierung der Benutzeroberfläche erfolgt beispielsweise im Hauptthread.
Dort verwenden Sie
dispatch_sync
//Do something dispatch_sync(queue, ^{ //Do something else }); //Do More Stuff
Hier hast du
//Do something
//Do something else
und//Do More stuff
getan nacheinander obwohl//Do something else
auf einem anderen Thread getan.Wenn Leute einen anderen Thread verwenden, besteht der gesamte Zweck normalerweise darin, dass etwas ausgeführt werden kann, ohne zu warten. Angenommen, Sie möchten große Datenmengen herunterladen, aber die Benutzeroberfläche reibungslos gestalten.
Daher wird dispatch_sync selten verwendet. Aber es ist da. Ich persönlich habe das nie benutzt. Fragen Sie nach einem Beispielcode oder Projekt, das dispatch_sync verwendet.
quelle
dispatch_sync
ist die Verwendung eines anderen asynchronen Prozesses als Rückruf. Beispielsweise kann die NSManagedObjectContext-performBlock
Methode von Core Data sie am Ende des Blocks als Rückruf verwenden.dispatch_sync entspricht semantisch einer herkömmlichen Mutex-Sperre.
dispatch_sync(queue, ^{ //access shared resource });
funktioniert genauso wie
pthread_mutex_lock(&lock); //access shared resource pthread_mutex_unlock(&lock);
quelle
David Gelhar hat nicht gesagt, dass sein Beispiel nur funktioniert, weil er stillschweigend eine serielle Warteschlange erstellt hat (in dispatch_queue_create wurde NULL übergeben, was DISPATCH_QUEUE_SERIAL entspricht).
Wenn Sie eine gleichzeitige Warteschlange erstellen möchten (um die gesamte Multithread-Leistung zu erhalten), führt sein Code aufgrund einer NSArray-Mutation (addObject :) während der Mutation (removeObjectAtIndex :) oder sogar eines schlechten Zugriffs (NSArray-Bereich über die Grenzen hinaus) zum Absturz. In diesem Fall sollten wir eine Barriere verwenden, um den exklusiven Zugriff auf das NSArray sicherzustellen, während beide Blöcke ausgeführt werden. Es schließt nicht nur alle anderen Schreibvorgänge in das NSArray aus, während es ausgeführt wird, sondern schließt auch alle anderen Lesevorgänge aus, wodurch die Änderung sicher wird.
Das Beispiel für eine gleichzeitige Warteschlange sollte folgendermaßen aussehen:
NSMutableArray *a = [[NSMutableArray alloc] init]; // All access to `a` is via this concurrent dispatch queue! dispatch_queue_t q = dispatch_queue_create("com.foo.samplequeue", DISPATCH_QUEUE_CONCURRENT); // append to array concurrently but safely and don't wait for block completion dispatch_barrier_async(q, ^{ [a addObject:something]; }); __block Something *first = nil; // pop 'Something first' from array concurrently and safely but wait for block completion... dispatch_barrier_sync(q, ^{ if ([a count] > 0) { first = [a objectAtIndex:0]; [a removeObjectAtIndex:0]; } }); // ... then here you get your 'first = [a objectAtIndex:0];' due to synchronised dispatch. // If you use async instead of sync here, then first will be nil.
quelle
Wenn Sie einige Beispiele für den praktischen Gebrauch wünschen, schauen Sie sich diese Frage an:
Wie löse ich diesen gelegentlich auftretenden Stillstand?
Ich löse es, indem ich sicherstelle, dass mein Haupt-ManagedObjectContext im Haupt-Thread erstellt wird. Der Prozess ist sehr schnell und es macht mir nichts aus zu warten. Nicht warten bedeutet, dass ich mich mit vielen Problemen der Vertraulichkeit befassen muss.
Ich benötige dispatch_sync, da Code für den Hauptthread ausgeführt werden muss. Dies ist der andere Thread als der, in dem der Code ausgeführt wird.
Wenn Sie also möchten, dass der Code 1. Wie gewohnt vorgeht. Sie möchten sich keine Sorgen um die Rennbedingungen machen. Sie möchten sicherstellen, dass der Code vollständig ist, bevor Sie fortfahren. 2. Fertig auf einem anderen Thread
Verwenden Sie dispatch_sync.
Wenn 1 verletzt wird, verwenden Sie dispatch_async. Wenn 2 verletzt wird, schreiben Sie einfach den Code wie gewohnt.
Bisher mache ich das nur einmal, nämlich wenn etwas am Haupt-Thread gemacht werden muss.
Also hier ist der Code:
+(NSManagedObjectContext *)managedObjectContext { NSThread *thread = [NSThread currentThread]; //BadgerNewAppDelegate *delegate = [BNUtilitiesQuick appDelegate]; //NSManagedObjectContext *moc = delegate.managedObjectContext; if ([thread isMainThread]) { //NSManagedObjectContext *moc = [self managedObjectContextMainThread]; return [self managedObjectContextMainThread]; } else{ dispatch_sync(dispatch_get_main_queue(),^{ [self managedObjectContextMainThread];//Access it once to make sure it's there }); } // a key to cache the context for the given thread NSMutableDictionary *managedObjectContexts =[self thread].managedObjectContexts; @synchronized(self) { if ([managedObjectContexts objectForKey:[self threadKey]] == nil ) { NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; threadContext.parentContext = [self managedObjectContextMainThread]; //threadContext.persistentStoreCoordinator= [self persistentStoreCoordinator]; //moc.persistentStoreCoordinator;// [moc persistentStoreCoordinator]; threadContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; [managedObjectContexts setObject:threadContext forKey:[self threadKey]]; } } return [managedObjectContexts objectForKey:[self threadKey]]; }
quelle
dispatch_sync wird hauptsächlich im dispatch_async-Block verwendet, um einige Operationen am Hauptthread auszuführen (z. B. update ui).
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //Update UI in main thread dispatch_sync(dispatch_get_main_queue(), ^{ self.view.backgroundColor = color; }); });
quelle
Hier ist ein halbwegs realistisches Beispiel. Sie haben 2000 Zip-Dateien, die Sie parallel analysieren möchten. Die Zip-Bibliothek ist jedoch nicht threadsicher. Daher werden alle Arbeiten, die die Zip-Bibliothek berühren, in die
unzipQueue
Warteschlange gestellt. (Das Beispiel ist in Ruby, aber alle Aufrufe werden direkt der C-Bibliothek zugeordnet. "Apply", z. B. Zuordnungen zu dispatch_apply (3) )#!/usr/bin/env macruby -w require 'rubygems' require 'zip/zipfilesystem' @unzipQueue = Dispatch::Queue.new('ch.unibe.niko.unzipQueue') def extractFile(n) @unzipQueue.sync do Zip::ZipFile.open("Quelltext.zip") { |zipfile| sourceCode = zipfile.file.read("graph.php") } end end Dispatch::Queue.concurrent.apply(2000) do |i| puts i if i % 200 == 0 extractFile(i) end
quelle
Ich habe die Dispatch-Synchronisierung innerhalb eines asynchronen Dispatches verwendet, um zu signalisieren, dass Änderungen an der Benutzeroberfläche zurück zum Haupt-Thread erfolgen.
Mein asynchroner Block hält sich nur wenig zurück und ich weiß, dass der Hauptthread die Änderungen an der Benutzeroberfläche kennt und diese ausführen wird. Wird im Allgemeinen in einem Verarbeitungsblock von Code verwendet, der einige CPU-Zeit benötigt, aber ich möchte weiterhin Änderungen an der Benutzeroberfläche innerhalb dieses Blocks vornehmen. Das Ausführen der Änderungen an der Benutzeroberfläche im asynchronen Block ist nutzlos, da die Benutzeroberfläche meines Erachtens auf dem Hauptthread ausgeführt wird. Wenn Sie sie auch als sekundäre asynchrone Blöcke oder als Selbstdelegierter ausführen, werden sie von der Benutzeroberfläche nur wenige Sekunden später angezeigt und es sieht verspätet aus.
Beispielblock:
dispatch_queue_t myQueue = dispatch_queue_create("my.dispatch.q", 0); dispatch_async(myQueue, ^{ // Do some nasty CPU intensive processing, load file whatever if (somecondition in the nasty CPU processing stuff) { // Do stuff dispatch_sync(dispatch_get_main_queue(),^{/* Do Stuff that affects UI Here */}); } });
quelle