Multithreading mit CoreData (Magical Record)

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Multithreading mit CoreData (Magical Record)

    Hallo zusammen,

    ich versuche mich momentan das erste mal an Backgroundthread und Multithread in Verbindung mit Core Data.
    Ich habe nun den Fall, dass der ganze Einleseprozess im Background ablaufen soll.
    Da die Werte gleichzeitig auch noch verschlüsselt werden sollen, möchte ich Multithreading nutzen.

    Hier einmal ein Beispiel:

    Quellcode

    1. localContext = [NSManagedObjectContext contextForCurrentThread];
    2. dispatch_queue_t bg_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    3. dispatch_async(bg_queue, ^{
    4. //Ausstattungslinie
    5. dispatch_apply([d_stammdaten[@"Ausstattungslinie"][@"ID"] count], bg_queue, ^(size_t i) {
    6. CD_Ausstattungslinie *ausstattungslinie = [CD_Ausstattungslinie createInContext:localContext];
    7. ausstattungslinie.id_index = [Verschluesselung encryptData:d_stammdaten[@"Ausstattungslinie"][@"ID"][i] setPasswort:encryptPass];
    8. ausstattungslinie.id_marke = [Verschluesselung encryptData:d_stammdaten[@"Ausstattungslinie"][@"Marke_ID"][i] setPasswort:encryptPass];
    9. ausstattungslinie.s_name = [Verschluesselung encryptData:d_stammdaten[@"Ausstattungslinie"][@"Name"][i] setPasswort:encryptPass];
    10. });
    11. //Fahrzeugart
    12. dispatch_apply([d_stammdaten[@"Fahrzeugart"][@"ID"] count], bg_queue, ^(size_t i) {
    13. CD_Fahrzeugart *fahrzeugart = [CD_Fahrzeugart createInContext:localContext];
    14. fahrzeugart.id_index = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugart"][@"ID"][i] setPasswort:encryptPass];
    15. fahrzeugart.s_name = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugart"][@"Name"][i] setPasswort:encryptPass];
    16. });
    17. //Fahrzeugbereich
    18. dispatch_apply([d_stammdaten[@"Fahrzeugbereich"][@"ID"] count], bg_queue, ^(size_t i) {
    19. CD_Fahrzeugbereich *fahrzeugbereich = [CD_Fahrzeugbereich createInContext:localContext];
    20. fahrzeugbereich.id_index = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugbereich"][@"ID"][i] setPasswort:encryptPass];
    21. fahrzeugbereich.s_name = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugbereich"][@"Name"][i] setPasswort:encryptPass];
    22. });
    23. //Fahrzeugherkunft
    24. dispatch_apply([d_stammdaten[@"Fahrzeugherkunft"][@"ID"] count], bg_queue, ^(size_t i) {
    25. CD_Fahrzeugherkunft *fahrzeugherkunft = [CD_Fahrzeugherkunft createInContext:localContext];
    26. fahrzeugherkunft.id_index = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugherkunft"][@"ID"][i] setPasswort:encryptPass];
    27. fahrzeugherkunft.s_name = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugherkunft"][@"Name"][i] setPasswort:encryptPass];
    28. });
    29. dispatch_async(dispatch_get_main_queue(), ^{
    30. //Speichern
    31. [localContext saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
    32. NSLog(@"Saved the database changes");
    33. }];
    34. });
    35. });
    Alles anzeigen


    Es kommt dann häufig beim Einlesen zu diesem Fehler:

    2014-05-14 08:40:28.507 twoSalesII[2791:1803] Esprit
    2014-05-14 08:40:28.592 twoSalesII[2791:60b] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)


    Was mache ich falsch bzw. muss ich noch beachten?

    Vielen Dank schon einmal im voraus für eure Hilfe.
  • kruemel1770 schrieb:

    localContext = [NSManagedObjectContext contextForCurrentThread];

    Ohne das Problem genauer analysiert zu haben, erscheint mir die Verwendung eines Thread-lokalen Kontexts in unterschiedlichen Threads doch sehr fragwürdig.

    BTW: Du parallelisierst explizit Dein Problem. Warum gehst Du implizit jedoch von einer teilweise seriellen Ausführung aus?
    „Meine Komplikation hatte eine Komplikation.“
  • Das ist nicht nur fragwürdig, das geht auch nicht. Steht auch ganz dick in den Core-Data-Concurrencys der entsprechend Apple Doku. Grundvoraussetzung das man CoreData in mehreren Threads benutzt ist, das jeder Thread seinen eigenen Context hat. Gesynct wird das Ganze dann über die entsprechenden Notifications.

    Ohne sich den entsprechenden Artikel mindestens 3x durchgelesen zu haben kann man das vergessen. Mich hat das beim ersten mal auch ziemlich viel Nerven gekostet.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Wahrscheinlich bringt die Parallelisierung mit so vielen Blocks auch keinen Vorteil. Wenn Du das Ganze (mit einer Schleife) in einem Block inklusive der kompletten Core-Data-Verwaltung (Create & Save) machst, vereinfacht sich die Core-Data-Verwaltung erheblich.
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    Wahrscheinlich bringt die Parallelisierung mit so vielen Blocks auch keinen Vorteil. Wenn Du das Ganze (mit einer Schleife) in einem Block inklusive der kompletten Core-Data-Verwaltung (Create & Save) machst, vereinfacht sich die Core-Data-Verwaltung erheblich.


    Vielen Dank für die Antwort!
    Nur kurz noch zum Verständnis: Welcher Part meines Code bezifferst du mit einem "Block"? Welche Codezeilen schließt du da mit ein. Nur die einzelnen Parts von "dispatch_apply" ?
  • So ungefährt?

    Quellcode

    1. dispatch_queue_t bg_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    2. dispatch_async(bg_queue, ^{
    3. //Ausstattungslinie
    4. for (int i = 0; i < [d_stammdaten[@"Ausstattungslinie"][@"ID"] count]; i++) {
    5. NSManagedObjectContext *localContext_test = [NSManagedObjectContext contextForCurrentThread];
    6. CD_Ausstattungslinie *ausstattungslinie = [CD_Ausstattungslinie createInContext:localContext];
    7. ausstattungslinie.id_index = [Verschluesselung encryptData:d_stammdaten[@"Ausstattungslinie"][@"ID"][i] setPasswort:encryptPass];
    8. ausstattungslinie.id_marke = [Verschluesselung encryptData:d_stammdaten[@"Ausstattungslinie"][@"Marke_ID"][i] setPasswort:encryptPass];
    9. ausstattungslinie.s_name = [Verschluesselung encryptData:d_stammdaten[@"Ausstattungslinie"][@"Name"][i] setPasswort:encryptPass];
    10. [localContext_test save:nil];
    11. }
    12. //Fahrzeugart
    13. for (int i = 0; i < [d_stammdaten[@"Fahrzeugart"][@"ID"] count]; i++) {
    14. NSManagedObjectContext *localContext_test = [NSManagedObjectContext contextForCurrentThread];
    15. CD_Fahrzeugart *fahrzeugart = [CD_Fahrzeugart createInContext:localContext];
    16. fahrzeugart.id_index = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugart"][@"ID"][i] setPasswort:encryptPass];
    17. fahrzeugart.s_name = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugart"][@"Name"][i] setPasswort:encryptPass];
    18. [localContext_test save:nil];
    19. }
    20. //Fahrzeugbereich
    21. for (int i = 0; i < [d_stammdaten[@"Fahrzeugbereich"][@"ID"] count]; i++) {
    22. NSManagedObjectContext *localContext_test = [NSManagedObjectContext contextForCurrentThread];
    23. CD_Fahrzeugbereich *fahrzeugbereich = [CD_Fahrzeugbereich createInContext:localContext];
    24. fahrzeugbereich.id_index = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugbereich"][@"ID"][i] setPasswort:encryptPass];
    25. fahrzeugbereich.s_name = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugbereich"][@"Name"][i] setPasswort:encryptPass];
    26. [localContext_test save:nil];
    27. }
    28. //Fahrzeugherkunft
    29. for (int i = 0; i < [d_stammdaten[@"Fahrzeugherkunft"][@"ID"] count]; i++) {
    30. NSManagedObjectContext *localContext_test = [NSManagedObjectContext contextForCurrentThread];
    31. CD_Fahrzeugherkunft *fahrzeugherkunft = [CD_Fahrzeugherkunft createInContext:localContext];
    32. fahrzeugherkunft.id_index = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugherkunft"][@"ID"][i] setPasswort:encryptPass];
    33. fahrzeugherkunft.s_name = [Verschluesselung encryptData:d_stammdaten[@"Fahrzeugherkunft"][@"Name"][i] setPasswort:encryptPass];
    34. [localContext_test save:nil];
    35. }
    36. dispatch_async(dispatch_get_main_queue(), ^{
    37. //Speichern
    38. [[NSManagedObjectContext contextForCurrentThread] saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
    39. NSLog(@"Saved the database changes");
    40. }];
    41. });
    42. });
    Alles anzeigen

  • kruemel1770 schrieb:

    Zum Thema Verarbeitungsgeschwindigkeit:
    • mit dispatch_apply-Aufrufen: ca. 5 Sekunden
    • ohne dispatch_apply-Aufrufen: ca. 10 Sekunden
    Deswegen verwunderte mich die Aussage: " Wahrscheinlich bringt die Parallelisierung mit so vielen Blocks auch keinen Vorteil."

    mit dispatch_apply 1 x sichern
    ohne dispatch_apply 5 x sichern

    Chris
    Man macht einfach solange irgendwelche Dinge, bis man tot ist.
    Und dann bekommen die anderen Kuchen.
  • Chris schrieb:

    kruemel1770 schrieb:

    Zum Thema Verarbeitungsgeschwindigkeit:
    • mit dispatch_apply-Aufrufen: ca. 5 Sekunden
    • ohne dispatch_apply-Aufrufen: ca. 10 Sekunden
    Deswegen verwunderte mich die Aussage: " Wahrscheinlich bringt die Parallelisierung mit so vielen Blocks auch keinen Vorteil."

    mit dispatch_apply 1 x sichern
    ohne dispatch_apply 5 x sichern

    Chris


    Damit ist die Nutzung von dispatch_apply doch sinnvoll oder verdrehe ich da gerade was?
  • Wenn ich es mitlogge, dann schaut es folgendermaßen aus:
    (Übrigens habe ich hier nur einmal eine Speicherung durchgeführt)

    Quellcode

    1. 2014-05-14 12:25:15.873 twoSalesII[3192:6003] Ausstattungslinie 0
    2. 2014-05-14 12:25:15.959 twoSalesII[3192:6003] Ausstattungslinie 1
    3. 2014-05-14 12:25:16.043 twoSalesII[3192:6003] Ausstattungslinie 2
    4. 2014-05-14 12:25:16.128 twoSalesII[3192:6003] Ausstattungslinie 3
    5. 2014-05-14 12:25:16.212 twoSalesII[3192:6003] Ausstattungslinie 4
    6. 2014-05-14 12:25:16.297 twoSalesII[3192:6003] Ausstattungslinie 5
    7. ...
    8. 2014-05-14 12:25:23.665 twoSalesII[3192:6003] Fahrzeugart 0
    9. 2014-05-14 12:25:23.722 twoSalesII[3192:6003] Fahrzeugart 1
    10. 2014-05-14 12:25:23.779 twoSalesII[3192:6003] Fahrzeugart 2
    11. 2014-05-14 12:25:23.836 twoSalesII[3192:6003] Fahrzeugart 3
    12. 2014-05-14 12:25:23.892 twoSalesII[3192:6003] Fahrzeugart 4
    13. 2014-05-14 12:25:23.949 twoSalesII[3192:6003] Fahrzeugart 5
    14. ...
    15. 2014-05-14 12:25:24.119 twoSalesII[3192:6003] Fahrzeugbereich 0
    16. 2014-05-14 12:25:24.176 twoSalesII[3192:6003] Fahrzeugbereich 1
    17. 2014-05-14 12:25:24.232 twoSalesII[3192:6003] Fahrzeugbereich 2
    18. 2014-05-14 12:25:24.289 twoSalesII[3192:6003] Fahrzeugbereich 3
    19. 2014-05-14 12:25:24.346 twoSalesII[3192:6003] Fahrzeugbereich 4
    20. 2014-05-14 12:25:24.403 twoSalesII[3192:6003] Fahrzeugbereich 5
    21. ...
    22. 2014-05-14 12:25:24.799 twoSalesII[3192:6003] Fahrzeugherkunft 0
    23. 2014-05-14 12:25:24.855 twoSalesII[3192:6003] Fahrzeugherkunft 1
    24. 2014-05-14 12:25:24.911 twoSalesII[3192:6003] Fahrzeugherkunft 2
    25. 2014-05-14 12:25:24.968 twoSalesII[3192:6003] Fahrzeugherkunft 3
    26. 2014-05-14 12:25:25.025 twoSalesII[3192:6003] Fahrzeugherkunft 4
    27. 2014-05-14 12:25:25.082 twoSalesII[3192:6003] Fahrzeugherkunft 5
    28. 2014-05-14 12:25:25.138 twoSalesII[3192:6003] Fahrzeugherkunft 6
    29. 2014-05-14 12:25:25.194 twoSalesII[3192:6003] Fahrzeugherkunft 7
    30. 2014-05-14 12:25:25.251 twoSalesII[3192:6003] Fahrzeugherkunft 8
    31. 2014-05-14 12:25:25.308 twoSalesII[3192:6003] Fahrzeugherkunft 9
    32. 2014-05-14 12:25:25.364 twoSalesII[3192:6003] Fahrzeugherkunft 10
    33. 2014-05-14 12:25:25.421 twoSalesII[3192:6003] Fahrzeugherkunft 11
    34. 2014-05-14 12:25:25.478 twoSalesII[3192:6003] Fahrzeugherkunft 12
    35. 2014-05-14 12:25:25.534 twoSalesII[3192:6003] Fahrzeugherkunft 13
    36. 2014-05-14 12:25:25.591 twoSalesII[3192:6003] Fahrzeugherkunft 14
    37. 2014-05-14 12:25:25.647 twoSalesII[3192:6003] Fahrzeugherkunft 15
    Alles anzeigen

  • Grundsätzlich schaut es gut aus :)
    Wenn ich aber "dispatch_apply" nutze, dann kann ich ungefähr 50% der Zeit einsparen:
    (Hier einmal mit "dispatch_apply")

    Quellcode

    1. 2014-05-14 12:34:50.474 twoSalesII[3208:4c0b] Ausstattungslinie 0
    2. 2014-05-14 12:34:50.474 twoSalesII[3208:3607] Ausstattungslinie 1
    3. 2014-05-14 12:34:50.594 twoSalesII[3208:4c0b] Ausstattungslinie 2
    4. 2014-05-14 12:34:50.594 twoSalesII[3208:3607] Ausstattungslinie 3
    5. 2014-05-14 12:34:50.682 twoSalesII[3208:3607] Ausstattungslinie 4
    6. 2014-05-14 12:34:50.685 twoSalesII[3208:4c0b] Ausstattungslinie 5
    7. ...
    8. 2014-05-14 12:34:54.575 twoSalesII[3208:4c0b] Fahrzeugart 0
    9. 2014-05-14 12:34:54.575 twoSalesII[3208:3607] Fahrzeugart 1
    10. 2014-05-14 12:34:54.635 twoSalesII[3208:3607] Fahrzeugart 3
    11. 2014-05-14 12:34:54.635 twoSalesII[3208:4c0b] Fahrzeugart 2
    12. 2014-05-14 12:34:54.693 twoSalesII[3208:3607] Fahrzeugart 4
    13. 2014-05-14 12:34:54.693 twoSalesII[3208:4c0b] Fahrzeugart 5
    14. ...
    15. 2014-05-14 12:34:54.810 twoSalesII[3208:3607] Fahrzeugbereich 1
    16. 2014-05-14 12:34:54.810 twoSalesII[3208:4c0b] Fahrzeugbereich 0
    17. 2014-05-14 12:34:54.869 twoSalesII[3208:4c0b] Fahrzeugbereich 2
    18. 2014-05-14 12:34:54.869 twoSalesII[3208:3607] Fahrzeugbereich 3
    19. 2014-05-14 12:34:54.927 twoSalesII[3208:4c0b] Fahrzeugbereich 4
    20. 2014-05-14 12:34:54.927 twoSalesII[3208:3607] Fahrzeugbereich 5
    21. ...
    22. 2014-05-14 12:34:55.162 twoSalesII[3208:4c0b] Fahrzeugherkunft 0
    23. 2014-05-14 12:34:55.162 twoSalesII[3208:3607] Fahrzeugherkunft 1
    24. 2014-05-14 12:34:55.222 twoSalesII[3208:4c0b] Fahrzeugherkunft 2
    25. 2014-05-14 12:34:55.223 twoSalesII[3208:3607] Fahrzeugherkunft 3
    26. 2014-05-14 12:34:55.283 twoSalesII[3208:4c0b] Fahrzeugherkunft 4
    27. 2014-05-14 12:34:55.287 twoSalesII[3208:3607] Fahrzeugherkunft 5
    28. 2014-05-14 12:34:55.346 twoSalesII[3208:4c0b] Fahrzeugherkunft 6
    29. 2014-05-14 12:34:55.350 twoSalesII[3208:3607] Fahrzeugherkunft 7
    30. 2014-05-14 12:34:55.404 twoSalesII[3208:4c0b] Fahrzeugherkunft 8
    31. 2014-05-14 12:34:55.408 twoSalesII[3208:3607] Fahrzeugherkunft 9
    32. 2014-05-14 12:34:55.461 twoSalesII[3208:4c0b] Fahrzeugherkunft 10
    33. 2014-05-14 12:34:55.466 twoSalesII[3208:3607] Fahrzeugherkunft 11
    34. 2014-05-14 12:34:55.519 twoSalesII[3208:4c0b] Fahrzeugherkunft 12
    35. 2014-05-14 12:34:55.524 twoSalesII[3208:3607] Fahrzeugherkunft 13
    36. 2014-05-14 12:34:55.578 twoSalesII[3208:4c0b] Fahrzeugherkunft 14
    37. 2014-05-14 12:34:55.583 twoSalesII[3208:3607] Fahrzeugherkunft 15
    Alles anzeigen
  • NSLog als Tool zur Laufzeitmessung zu nutzen ist aber auch mehr so π*Daumen…
    Du kannst Dir nie sicher sein, warum die Zeiten abweichen.
    Instruments wäre da ein verlässlicheres Tool.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P