我已經瀏覽了很多關於在多個線程中執行核心數據操作,但沒有好運氣來解決我的問題。在自己創建的多個線程中執行核心數據操作以節省處理時間
我的代碼是這樣的,我必須每隔10分鐘下載一個csv文件,其中包含每個10秒的條目。這個文件一旦下載就被解析,並且內容被保存在數據庫中,然後文件被刪除,當需要時,我可以從數據庫中獲取數據。
現在,我現在有一個超過一個月的巨大現有內容,隨着時間的推移,這些內容可能會延長到數年,執行將新文件保存到數據庫和將對象從核心數據提取到數組中的巨大任務已經使用單個線程下載文件造成了巨大的處理時間。此外,應用程序中的視圖需要根據以前的所有數據進行調整(它們基本上是數量與時間的關係圖)。
如何在多個線程中實現此目的並優化我的代碼處理時間並將UI阻塞降至最低?
請注意:在後臺線程中執行任務不是我關心的問題,因爲我無論如何都不得不根據總數據顯示圖形。請提供寶貴的建議。
編輯:執行了一些多線程 這裏是新代碼,
- (void) downloadFiles:(NSString *)dataPath{
__block AppDelegate *appD = (AppDelegate *)[[UIApplication sharedApplication] delegate];
backgroundMOC = [[NSManagedObjectContext alloc] init];
[backgroundMOC setPersistentStoreCoordinator:[[appD managedObjectContext] persistentStoreCoordinator]];
if (parsedDetailsDataArrayForCurrentDay) {
parsedDetailsDataArrayForCurrentDay = nil;
}
if (parsedDetailsDataArrayForCurrentMonth) {
parsedDetailsDataArrayForCurrentMonth = nil;
}
if (parsedDetailsDataArrayForCurrentYear) {
parsedDetailsDataArrayForCurrentYear = nil;
}
parsedDetailsDataArrayForCurrentDay = [[NSMutableArray alloc] init];
parsedDetailsDataArrayForCurrentMonth = [[NSMutableArray alloc] init];
parsedDetailsDataArrayForCurrentYear = [[NSMutableArray alloc] init];
dispatch_group_t d_group = dispatch_group_create();
for (NSInteger i = 0; i <= (self.filesListArray.count - 1); i++) {
NSString *filePathOnPhone = [dataPath stringByAppendingString:[NSString stringWithFormat:@"/%@", [[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"]]];
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:@"ParsedInfiDetails"];
NSString *nameToGet = [[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"];
NSLog(@"File Check: %@", nameToGet);
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"fileName = %@", nameToGet];
[fetch setPredicate:predicate];
NSError *error = nil;
NSArray *results = [backgroundMOC executeFetchRequest:fetch error:&error];
NSArray *definedResults = [results copy];
if(definedResults && (definedResults.count !=0)) {
NSLog(@"Entities with that name: %@", results);
@autoreleasepool {
NSArray *result = [[definedResults sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modDate" ascending:YES]]] copy];
NSDate *specificDate = [NSDate date];
NSMutableArray *sortedDateArray = [[NSMutableArray alloc] init];
NSMutableArray *sortedDateCurrentYearArray = [[NSMutableArray alloc] init];
NSMutableArray *sortedDateCurrentMonthArray = [[NSMutableArray alloc] init];
for (int i = 0; i < result.count; i++) {
NSManagedObject *obj = [result objectAtIndex:i];
NSDate *objDate = [obj valueForKey:@"modDate"];
NSCalendar *gregorian = [NSCalendar currentCalendar];
NSDateComponents *components = [gregorian componentsInTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"] fromDate:objDate];
NSInteger day = [components day];
NSInteger month = [components month];
NSInteger year = [components year];
NSDateComponents *specificComps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:specificDate];
NSInteger specificDay = [specificComps day];
NSInteger specificMonth = [specificComps month];
NSInteger specificYear = [specificComps year];
if(day == 24){
}
if (day == specificDay && month == specificMonth && year == (specificYear-2000)) {
[sortedDateArray addObject:obj];
}
NSDate *todayDate = [NSDate date];
NSDateComponents *componentsForToday = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:todayDate];
NSInteger currentMonth = [componentsForToday month];
NSInteger currentYear = [componentsForToday year];
if (year == (currentYear-2000)) {
[sortedDateCurrentYearArray addObject:obj];
}
if (year == (currentYear -2000) && month == currentMonth) {
[sortedDateCurrentMonthArray addObject:obj];
}
}
NSMutableArray *sortedTimedArray = [[NSMutableArray alloc] initWithArray:[sortedDateArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];
NSMutableArray *sortedTimedCurrentYearArray = [[NSMutableArray alloc] initWithArray:[sortedDateCurrentYearArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];
NSMutableArray *sortedTimedCurrentMonthArray = [[NSMutableArray alloc] initWithArray:[sortedDateCurrentMonthArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];
[parsedDetailsDataArrayForCurrentDay addObjectsFromArray:sortedTimedArray];
[parsedDetailsDataArrayForCurrentYear addObjectsFromArray:sortedTimedCurrentYearArray];
[parsedDetailsDataArrayForCurrentMonth addObjectsFromArray:sortedTimedCurrentMonthArray];
}
} else {
NSLog(@"Error: %@", error);
NSString *threadName = [NSString stringWithFormat:@"%ld THREAD", (long)i];
dispatch_queue_t myQueue = dispatch_queue_create([threadName UTF8String], NULL);
dispatch_group_async(d_group, myQueue, ^{
NSManagedObjectContext *backgroundMOC1;
backgroundMOC1 = [[NSManagedObjectContext alloc] init];
[backgroundMOC1 setPersistentStoreCoordinator:[[appD managedObjectContext] persistentStoreCoordinator]];
NSLog(@"Entered Thread ");
BOOL success = [appD.ftpManager downloadFile:[[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"] toDirectory:[NSURL URLWithString:dataPath] fromServer:srv];
if (success) {
// dispatch_group_async(d_group, myQueue, ^{
NSMutableDictionary *dict = [appD.ftpManager progress];
NSString *filePath = [dataPath stringByAppendingString:[NSString stringWithFormat:@"/%@", [[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"]]];
CHCSVParser *parser = [[CHCSVParser alloc] initWithContentsOfCSVURL:[NSURL fileURLWithPath:filePath]];
[parser parse];
NSMutableArray *currentFileComponentsArray = [NSArray arrayWithContentsOfCSVURL:[NSURL fileURLWithPath:filePath]];
NSMutableArray *parsedDetailsEntitiesArray = [[NSMutableArray alloc] init];
for (int j = 1; j <= (currentFileComponentsArray.count-1); j++) {
NSArray *detailsArray = [currentFileComponentsArray objectAtIndex:j];
if (!(detailsArray.count < 32)) {
NSManagedObject *parsedDetails = [NSEntityDescription
insertNewObjectForEntityForName:@"ParsedInfiDetails"
inManagedObjectContext:[appD managedObjectContext]];
NSString *totalDateString = [NSString stringWithFormat:@"%@ %@", [detailsArray objectAtIndex:0], [detailsArray objectAtIndex:1]];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"dd/MM/yyyy HH:mm:ss";
NSTimeZone *gmt = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
[dateFormatter setTimeZone:gmt];
NSDate *startDate = [dateFormatter dateFromString:totalDateString];
[parsedDetails setValue:startDate forKey:@"modDate"];
[parsedDetails setValue:startDate forKey:@"modTime"];
———————————————————————PERFORM PARSEDDETAILS STATEMENTS----------------
NSError *error;
NSLog(@"Saved File in Database: %@", [[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"]);
NSLog(@"Saved thread");
if (![backgroundMOC1 save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
else{
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
//if the download fails, we try to delete the empty file created by the stream.
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
//when data is stored in coredata remove the downloaded file.
}
[parsedDetailsEntitiesArray addObject:parsedDetails];
}
}
}
NSSet *set = [[NSSet alloc] initWithArray:parsedDetailsEntitiesArray];
[self.relevantInverId setValue:set forKey:@"infiDetails"];
NSDate *specificDate = [NSDate date];
@autoreleasepool {
NSMutableArray *sortedDateArray = [[NSMutableArray alloc] init];
NSMutableArray *sortedDateCurrentYearArray = [[NSMutableArray alloc] init];
NSMutableArray *sortedDateCurrentMonthArray = [[NSMutableArray alloc] init];
for (int i = 0; i < parsedDetailsEntitiesArray.count; i++) {
NSManagedObject *obj = [parsedDetailsEntitiesArray objectAtIndex:i];
NSDate *objDate = [obj valueForKey:@"modDate"];
NSCalendar *gregorian = [NSCalendar currentCalendar];
NSDateComponents *components = [gregorian componentsInTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"] fromDate:objDate];
NSInteger day = [components day];
NSInteger month = [components month];
NSInteger year = [components year];
NSDateComponents *specificComps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:specificDate];
NSInteger specificDay = [specificComps day];
NSInteger specificMonth = [specificComps month];
NSInteger specificYear = [specificComps year];
if(day == 24){
}
if (day == specificDay && month == specificMonth && year == (specificYear-2000)) {
[sortedDateArray addObject:obj];
}
NSDate *todayDate = [NSDate date];
NSDateComponents *componentsForToday = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:todayDate];
NSInteger currentMonth = [componentsForToday month];
NSInteger currentYear = [componentsForToday year];
if (year == (currentYear-2000)) {
[sortedDateCurrentYearArray addObject:obj];
}
if (year == (currentYear-2000) && month == currentMonth) {
[sortedDateCurrentMonthArray addObject:obj];
}
}
NSMutableArray *sortedTimedArray = [[NSMutableArray alloc] initWithArray:[sortedDateArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];
[parsedDetailsDataArrayForCurrentDay addObjectsFromArray:sortedTimedArray];
NSMutableArray *sortedTimedCurrentYearArray = [[NSMutableArray alloc] initWithArray:[sortedDateCurrentYearArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];
NSMutableArray *sortedTimedCurrentMonthArray = [[NSMutableArray alloc] initWithArray:[sortedDateCurrentMonthArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];
[parsedDetailsDataArrayForCurrentYear addObjectsFromArray:sortedTimedCurrentYearArray];
[parsedDetailsDataArrayForCurrentMonth addObjectsFromArray:sortedTimedCurrentMonthArray];
}
// });
}
});
}
BOOL isFileAlreadyPresent = [[NSFileManager defaultManager] fileExistsAtPath:filePathOnPhone];
}
NSMutableArray *sortedParsedDetailsArrayForCurrentDay = [[NSMutableArray alloc] initWithArray:[parsedDetailsDataArrayForCurrentDay sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];
NSDate *startDate ;
NSDate *endaDate;
dispatch_group_notify(d_group, dispatch_get_main_queue(), ^{
dispatch_async(dispatch_get_main_queue(), ^{
[self stopLogoSpin];
[hud dismiss];
});
NSLog(@"All background tasks are done!!");
});
}
現在,日誌@ 「輸入的主題」 是可見的日誌,但是,@ 「保存的文件在數據庫:%@」,[ self.filesListArray objectAtIndex:i]和@「保存的線程」不會被調用。
此外,
BOOL success = [appD.ftpManager downloadFile:[[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"] toDirectory:[NSURL URLWithString:dataPath] fromServer:srv];
幫助下載文件與下載方法的單獨的線程。 應該取消註釋以下的幫助嗎?
// dispatch_group_async(d_group, myQueue, ^{
主線程有意地等待,但低於該塊也不會被調用:
dispatch_group_notify(d_group, dispatch_get_main_queue(), ^{
dispatch_async(dispatch_get_main_queue(), ^{
[self stopLogoSpin];
[radialHUD dismiss];
});
NSLog(@"All background tasks are done!!");
});
請諮詢上述任何修改和解決問題的方法。
當然,這是一個比線程問題更多的磁盤I/O問題?核心數據不是我的強項,但可能會優化如何將數據寫入數據庫/讀取應該優化,如果它可以是 – Fonix
是@Fonix:這正是關注的問題。它需要很長時間來處理。我猜,多線程可以幫助我,其中我需要爲每個輸入提供一個增量ID,然後在提取時我需要將多個線程分成多個線程,並在ID範圍內分叉。但我不確定如何去做,或者如果這有幫助。 –
我不認爲線程能夠幫助磁盤I/O,甚至可能會減慢它的速度,但是也許你可以讀入大塊數據,然後在一個單獨的線程中開始處理它,同時加載下一個塊。取決於加工的密集程度是否值得。不能根據你提供的信息說得太多,而且我也不太瞭解核心數據,所以其他人可能不得不幫你 – Fonix