主线程在 viewDidLoad 中的并发队列上做 dispatch_async,或者在方法内做事
main thread does dispatch_async on a concurrent queue in viewDidLoad, or within a method matters
所以在一些帮助下,我更加清楚嵌套 GCD 在我的程序中是如何工作的。
原文post位于:
然而,你不需要通过原来的post,但基本上这里的代码运行s数据库在后台执行并且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 不再响应:
//一些数据库单例class
//串行队列在class的私有扩展中声明。并在 init()
中创建
-(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 组合触及。为什么当我用 object/method 包装它时,我必须使用 dispatch_async(dispatch_get_main_queue()...) ?
似乎我的主线程是否在并发队列上执行 dispatch_async
在 viewDidLoad 中,或在方法中,确实很重要。
我认为主线程正在将所有这些 testInsert 方法推送到它的线程堆栈中。然后这些方法必须由主线程处理。因此,即使 dispatch_sync 没有阻塞主线程,主线程 运行s 到 viewDidLoad 的末尾,并且必须等待所有 testInsert 方法被处理和完成才能继续主队列中的下一个任务??
备注
所以我回到家再次测试:
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时,UI没有被阻塞。我在后台看到我的数据库操作处理。
然后当循环为64时,UI被阻塞1次数据库操作,然后returns没问题。
当我使用 65 时,UI 冻结了 2 个数据库操作,然后 returns 没问题...
当我使用 80 之类的东西时,它会从 64-80 被阻止...所以我等了 16 秒后我的 UI 才响应。
当时我想不通为什么是64。所以现在我知道它同时允许64个并发线程。 ...并且与将其包装在 object/method 中无关。 :D
非常感谢贡献者的大力帮助!
There is a hard limit of 64 GCD concurrent operations(每个顶级并发队列)可以 运行 在一起。
发生的事情是您向并发队列提交 超过 64 个块,每个块都被 [NSThread sleepForTimeInterval:1.0f]
阻塞,从而强制创建一个新线程对于每个操作。 因此,一旦达到线程限制,它就会备份并开始阻塞主线程。
我已经用 100 个“数据库写入”操作(在设备上)对此进行了测试,主线程似乎被阻塞,直到发生了 36 个操作(现在只剩下 64 个操作,因此主线程现在是un-blocked).
使用单例不会给您带来任何问题,因为您是同步调用方法的,因此不应该有线程冲突。
最简单的解决方案就是为您的“数据库写入”操作使用单个后台串行队列。这样,只创建一个线程来处理操作。
- (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(), ^() {}
对你有用...我只能假设它是 off-loading 直到界面加载后的“数据库写入” .
有关线程和 GCD 的更多资源
Number of threads created by GCD?
-
-
所以在一些帮助下,我更加清楚嵌套 GCD 在我的程序中是如何工作的。
原文post位于:
然而,你不需要通过原来的post,但基本上这里的代码运行s数据库在后台执行并且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 不再响应:
//一些数据库单例class
//串行队列在class的私有扩展中声明。并在 init()
中创建-(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 组合触及。为什么当我用 object/method 包装它时,我必须使用 dispatch_async(dispatch_get_main_queue()...) ?
似乎我的主线程是否在并发队列上执行 dispatch_async 在 viewDidLoad 中,或在方法中,确实很重要。
我认为主线程正在将所有这些 testInsert 方法推送到它的线程堆栈中。然后这些方法必须由主线程处理。因此,即使 dispatch_sync 没有阻塞主线程,主线程 运行s 到 viewDidLoad 的末尾,并且必须等待所有 testInsert 方法被处理和完成才能继续主队列中的下一个任务??
备注
所以我回到家再次测试:
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时,UI没有被阻塞。我在后台看到我的数据库操作处理。
然后当循环为64时,UI被阻塞1次数据库操作,然后returns没问题。
当我使用 65 时,UI 冻结了 2 个数据库操作,然后 returns 没问题...
当我使用 80 之类的东西时,它会从 64-80 被阻止...所以我等了 16 秒后我的 UI 才响应。
当时我想不通为什么是64。所以现在我知道它同时允许64个并发线程。 ...并且与将其包装在 object/method 中无关。 :D
非常感谢贡献者的大力帮助!
There is a hard limit of 64 GCD concurrent operations(每个顶级并发队列)可以 运行 在一起。
发生的事情是您向并发队列提交 超过 64 个块,每个块都被 [NSThread sleepForTimeInterval:1.0f]
阻塞,从而强制创建一个新线程对于每个操作。 因此,一旦达到线程限制,它就会备份并开始阻塞主线程。
我已经用 100 个“数据库写入”操作(在设备上)对此进行了测试,主线程似乎被阻塞,直到发生了 36 个操作(现在只剩下 64 个操作,因此主线程现在是un-blocked).
使用单例不会给您带来任何问题,因为您是同步调用方法的,因此不应该有线程冲突。
最简单的解决方案就是为您的“数据库写入”操作使用单个后台串行队列。这样,只创建一个线程来处理操作。
- (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(), ^() {}
对你有用...我只能假设它是 off-loading 直到界面加载后的“数据库写入” .
有关线程和 GCD 的更多资源
Number of threads created by GCD?