gpt4 book ai didi

ios - 主线程在 viewDidLoad 中的并发队列上执行 dispatch_async,或者在方法内执行事务

转载 作者:可可西里 更新时间:2023-11-01 05:43:22 24 4
gpt4 key购买 nike

因此,在一些帮助下,我更加清楚嵌套 GCD 在我的程序中是如何工作的。

原帖在:

Making sure I'm explaining nested GCD correctly

但是,您不需要阅读原始帖子,但基本上这里的代码在后台运行数据库执行并且 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 不再响应:

//一些数据库单例类

//串行队列在类的私有(private)扩展中声明。并在 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 组合触及。为什么当我将它包装在一个对象/方法中时,我必须使用 dispatch_async(dispatch_get_main_queue()...) ?

似乎我的主线程是否在并发队列上执行 dispatch_async在 viewDidLoad 中,或在方法中,确实很重要。

我认为主线程正在将所有这些 testInsert 方法推送到其线程堆栈中。然后这些方法必须由主线程处理。因此,即使 dispatch_sync 没有阻塞主线程,主线程运行到 viewDidLoad 的末尾,并且必须等待所有 testInsert 方法被处理和完成才能移动到 Main Queue 中的下一个任务?

注意事项

所以我回到家再次测试:

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 个数据库操作,然后返回正常。

当我使用 65 时,UI 会卡住 2 个数据库操作,然后返回正常...

当我使用 80 之类的东西时,它会从 64-80 被阻止...所以我等待 16 秒,然后我的 UI 才会响应。

当时我想不通为什么是64。所以现在我知道它的同时允许64个并发线程。 ...并且与将其包装在对象/方法中无关。 :D

非常感谢贡献者的大力帮助!

最佳答案

There is a hard limit of 64 GCD concurrent operations (每个顶级并发队列)可以一起运行。

发生的事情是你向你的并发队列提交超过 64 个 block ,每个 block 都被 [NSThread sleepForTimeInterval:1.0f] 阻塞,迫使一个新的为每个操作创建线程。 因此,一旦达到线程限制,它就会备份并开始阻塞主线程。

我已经用 100 个“数据库写入”操作(在设备上)对此进行了测试,并且主线程似乎被阻塞,直到发生了 36 个操作(现在只剩下 64 个操作,因此主线程现在未-被阻止)。

使用单例不会给您带来任何问题,因为您是同步调用方法的,因此不应该有线程冲突。

最简单的解决方案就是为您的“数据库写入”操作使用单个后台串行队列。这样一来,只会创建一个线程来处理操作。

- (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 的更多资源

关于ios - 主线程在 viewDidLoad 中的并发队列上执行 dispatch_async,或者在方法内执行事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34849078/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com