关于在多个线程中执行核心数据操作,我已经冲浪了很多,但是没有好运来解决我的问题。
我的代码是这样的,我必须每10分钟下载一个csv文件,其中包含10秒的每个条目。下载后,该文件将被解析,并将内容保存在数据库中,然后将其删除,然后在需要时,我可以从数据库中获取数据。
现在,我已有一个多月的大量现有内容,随着时间的流逝可能还会延长到几年,执行这项庞大的任务,将新文件保存到数据库,并使用以下命令将核心数据中的对象提取到阵列中,以供已下载文件使用一个线程会导致大量的处理时间。此外,应用程序中的 View 需要使用所有以前的数据进行调整(它们基本上是数量与时间的关系图)。
如何在多个线程中实现这一目标,并优化代码处理时间并将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!!");
});
}
现在,日志@“Entered Thread”在日志中可见,但是@“[数据库中保存的文件:%@”,[[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!!");
});
请为上述问题提供任何修改和解决方案的建议。
最佳答案
通过将循环中不需要的所有内容移到外部并使用GCD执行循环操作来优化代码。
dispatch_queue_t myOwnQueue = dispatch_queue_create([@"MyOwnQueue" UTF8String], NULL);
dispatch_apply(self.filesListArray.count, myOwnQueue, ^(size_t i) { });
这导致时间减少了一半。但是,还需要进一步优化。