主线程在viewDidLoad中的一个并发队列上执行dispatch_async,或者在一个方法内部执行

所以在一些帮助下,我更清楚地知道嵌套的GCD在我的程序中是如何工作的。

原帖是:

确保我正确地解释嵌套的GCD

但是,您不需要阅读原始文章,但基本上这里的代码在后台运行数据库执行,并且UI是响应式的:

-(void)viewDidLoad { dispatch_queue_t concurrencyQueue = dispatch_queue_create("com.epam.halo.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t serialQueue = dispatch_queue_create("com.epam.halo.queue2", DISPATCH_QUEUE_SERIAL); for ( int i = 0; i < 10; i++) { dispatch_async(concurrencyQueue, ^() { NSLog(@"START insertion method%d <--", i); dispatch_sync(serialQueue, ^() { //this is to simulate writing to database NSLog(@"----------START %d---------", i); [NSThread sleepForTimeInterval:1.0f]; NSLog(@"--------FINISHED %d--------", i); }); NSLog(@"END insertion method%d <--", i); }); } } 

但是,当我开始重构它们并将它们放入方法并使所有内容看起来不错时,UI不再响应:

//一些数据库单例类

//串行队列在类的私有扩展中声明。 并在init()中创build

 -(void)executeDatabaseStuff:(int)i { dispatch_sync(serialQueue, ^() { //this is to simulate writing to database NSLog(@"----------START--------- %d", i); [NSThread sleepForTimeInterval:1.0f]; NSLog(@"--------FINISHED-------- %d", i); }); } -(void)testInsert:(int)i { dispatch_async(concurrencyQueue, ^() { [self executeDatabaseStuff:i]; }); } 

//ViewController.m

 - (void)viewDidLoad { //UI is unresponsive :( for ( int i = 0; i < totalNumberOfPortfolios; i++) { NSLog(@"START insertion method%d <--", i); [[DatabaseFunctions sharedDatabaseFunctions] testInsert: i]; NSLog(@"END insertion method%d <--", i); } } 

使重构版本工作的唯一方法是当我把dispatch_async(dispatch_get_main_queue():

 for ( int i = 0; i < totalNumberOfPortfolios; i++) { dispatch_async(dispatch_get_main_queue(), ^() { NSLog(@"START insertion method%d <--", i); [[DatabaseFunctions sharedDatabaseFunctions] testInsert: i]; NSLog(@"END insertion method%d <--", i); }); } 

所以我的问题是,我认为我使用dispatch_async concurrencyQueue事实将确保我的主线程不被dispatch_sync serialQueue组合触及。 为什么当我把它包装在对象/方法中时,我必须使用dispatch_async(dispatch_get_main_queue()…)?

看来,我的主线程dispatch_async在viewDidLoad,或在一个方法内的并发队列,确实很重要。

我在想,主线程将所有这些testInsert方法推到它的线程堆栈上。 这些方法必须由主线程处理。 因此,即使dispatch_sync没有阻塞主线程,主线程也会运行到viewDidLoad的末尾,并且必须等待所有的testInsert方法被处理和完成,然后才能移到主队列中的下一个任务。

笔记

所以我回到家,再次testing它:

 for ( int i = 0; i < 80; i++) { NSLog(@"main thread %d <-- ", i); dispatch_async(concurrencyQueue, ^() { [NSThread isMainThread] ? NSLog(@"its the main thread") : NSLog(@"not main thread"); NSLog(@"concurrent Q thread %i <--", i); dispatch_sync(serialQueue, ^() { //this is to simulate writing to database NSLog(@"serial Q thread ----------START %d---------", i); [NSThread sleepForTimeInterval:1.0f]; NSLog(@"serial Q thread --------FINISHED %d--------", i); }); NSLog(@"concurrent Q thread %i -->", i); }); NSLog(@"main thread %d --> ", i); } //for loop 

当我从1 – 63运行循环,用户界面不被阻止。 我在后台看到我的数据库操作处理。

然后当循环为64时,UI被阻塞1次数据库操作,然后返回罚款。

当我使用65,UI冻结2数据库操作,然后返回罚款…

当我使用类似于80的东西时,它会被阻挡在64-80之间…所以我等了16秒,然后我的UI才响应。

当时,我不知道为什么64.所以现在我知道它的64个并发线程一次允许。 …与将其包装在一个对象/方法中无关。 :d

非常感谢来自贡献者的真棒帮助!

64个GCD并发操作 (每个顶级并发队列)可以一起运行,但是有一个硬限制 。

发生了什么事是你提交超过64个块到你的并发队列,他们每个都被[NSThread sleepForTimeInterval:1.0f]阻塞,强制为每个操作创build一个新的线程。 因此,一旦达到线程限制,就会备份并开始阻塞主线程。

我已经用100个“数据库写入”操作(在设备上)testing了这一点,主线程似乎被阻塞,直到发生了36次操作(现在只有64次操作,因此主线程现在未被阻塞)。

单身人士的使用不应该引起任何问题,因为你正在同步调用方法,所以不应该有线程冲突。

最简单的解决方法就是使用单个后台串行队列来执行“数据库写入”操作。 这样,只有一个线程正在被创build来处理操作。

 - (void)viewDidLoad { [super viewDidLoad]; static dispatch_once_t t; dispatch_once(&t, ^{ serialQueue = dispatch_queue_create("com.epam.halo.queue2", DISPATCH_QUEUE_SERIAL); }); for (int i = 0; i < 100; i++) { [self testInsert:i]; } } -(void)executeDatabaseStuff:(int)i { //this is to simulate writing to database NSLog(@"----------START--------- %d", i); [NSThread sleepForTimeInterval:1.0f]; NSLog(@"--------FINISHED-------- %d", i); } -(void)testInsert:(int)i { NSLog(@"Start insert.... %d", i); dispatch_async(serialQueue, ^() { [self executeDatabaseStuff:i]; }); NSLog(@"End insert... %d", i); } 

我不知道为什么在您的for循环中插入dispatch_async(dispatch_get_main_queue(), ^() {}为您工作…我只能假设它正在卸载“数据库写入”,直到接口加载后。

线程和GCD上的更多资源