在条件循环中调度队列的问题
Trouble with dispatching queues in a conditional loop
-(void) sample
{
dispatch_queue_t aQueue = dispatch_queue_create("hello-world", NULL);
__block int j=0;
for(int i=0; i<3; ++i){
dispatch_sync(aQueue, ^{
j++;
NSLog(@"I'm in Loop\n");
if(j==2)
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"I'm in main for the first time\n");
});
});
}
dispatch_sync(aQueue, ^{
NSLog(@"I'm in the second task of aQueue\n");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"I'm just about to exit from the main thread\n");
});
});
}
输出:
2016-02-02 17:11:16.226 facebookCustom Post[5078:227956] I'm in Loop
2016-02-02 17:11:16.227 facebookCustom Post[5078:227956] I'm in Loop
2016-02-02 17:11:16.227 facebookCustom Post[5078:227956] I'm in Loop
2016-02-02 17:11:16.227 facebookCustom Post[5078:227840] I'm in the second task of aQueue
2016-02-02 17:11:16.426 facebookCustom Post[5078:227840] I'm in main for the first time
2016-02-02 17:11:16.426 facebookCustom Post[5078:227840] I'm just about to exit from the main thread
代码的输出让我非常惊讶,因为在第一个任务完成之前不应该执行任务,因为我们是第一次同步调度队列,对吗?那怎么会在I'm in main for the first time
之前打印出I'm in the second task of aQueue
呢?
我相信在 this question 的答案中可以更完整地回答这个问题,并且与 GCD 实现中的优化有关。
作为优化,这些块正在当前(主)线程上执行,而不是在 aQueue
上执行,因此通过 dispatch_get_main_queue()
的任何调用都是 "queued up"(请原谅双关语)稍后执行,我认为在 运行-loop.
的下一次迭代中
您可以通过使用 NSLog()
而不是 printf()
进行日志记录来获取更多信息,因为这将打印线程 ID。请使用该输出更新您的问题。
这就是我目前所知道的全部内容,也许@bbum 会路过并用更好的答案进行澄清。
顺便说一句,这是个好问题。
因为 printf 不需要在调用时准确地将字符显示在屏幕上。每个线程都可以收集 printf 输出,并在需要时将其显示在屏幕上。这通常更有效率。
在 printf 调用上设置断点,调用将按照您期望的顺序执行。 printf 不定义从多个线程调用时的输出顺序。
,这是因为你用 dispatch_sync
到 aQueue
阻塞了主线程,因此你的第一个 NSLog
到主线程被推迟到你的方法完成后 运行ning.
另外,你的做法是完全错误的。在大多数情况下,使用 dispatch_sync
从另一个串行队列到一个串行队列是完全多余的,因为在另一个串行队列完成之前,原始队列将被阻止运行。 它还有造成线程死锁的风险,因此您应该尽可能使用 dispatch_async
。
As said by this answer,当从主线程使用 dispatch_sync
到另一个串行队列时,在大多数情况下,GCD 只会在主线程上 运行 这个,因为传输很昂贵它。
但是我不确定您在这里使用 GCD 试图达到什么目的。您拥有的代码不比 运行 将所有内容都放在主线程上(因为这是最有可能在幕后发生的事情)。
如果您只是想将任务卸载到单独的线程上,那么您需要使用 dispatch_async
.
此外,如果您希望输出以可靠的顺序发生,您可以对主线程使用 dispatch_sync
(是的,我在这里对我的规则进行了例外处理,但只是因为它是单个 NSLog
),从而保证第一个主线程日志发生在下一个之前(并且不会导致死锁,因为您正在使用 dispatch_async
aQueue
).
-(void) sample
{
dispatch_queue_t aQueue = dispatch_queue_create("hello-world", DISPATCH_QUEUE_SERIAL); // I changed the attr parameter from NULL to DISPATCH_QUEUE_SERIAL for increased readability.
__block int j=0;
for(int i=0; i<3; ++i){
dispatch_async(aQueue, ^{
j++;
NSLog(@"I'm in Loop\n");
if(j==2)
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"I'm in main for the first time\n");
});
});
}
dispatch_async(aQueue, ^{
NSLog(@"I'm in the second task of aQueue\n");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"I'm just about to exit from the main thread\n");
});
});
}
现在的输出是:
2016-02-02 12:06:46.573 gcd test again[2351:2465744] I'm in Loop
2016-02-02 12:06:46.573 gcd test again[2351:2465744] I'm in Loop
2016-02-02 12:06:46.580 gcd test again[2351:2465707] I'm in main for the first time
2016-02-02 12:06:46.581 gcd test again[2351:2465744] I'm in Loop
2016-02-02 12:06:46.581 gcd test again[2351:2465744] I'm in the second task of aQueue
2016-02-02 12:06:46.581 gcd test again[2351:2465707] I'm just about to exit from the main thread
这样,主线程可以继续 运行,只是被打断以确保您的 NSLog
调用以正确的顺序分派。
但是,我绝不会推荐使用主队列“只是为了同步一些调用”。实际上,您应该为此使用一个单独的串行队列。
我希望这是有道理的。即使在最好的时候,GCD 也会令人困惑!
-(void) sample
{
dispatch_queue_t aQueue = dispatch_queue_create("hello-world", NULL);
__block int j=0;
for(int i=0; i<3; ++i){
dispatch_sync(aQueue, ^{
j++;
NSLog(@"I'm in Loop\n");
if(j==2)
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"I'm in main for the first time\n");
});
});
}
dispatch_sync(aQueue, ^{
NSLog(@"I'm in the second task of aQueue\n");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"I'm just about to exit from the main thread\n");
});
});
}
输出:
2016-02-02 17:11:16.226 facebookCustom Post[5078:227956] I'm in Loop
2016-02-02 17:11:16.227 facebookCustom Post[5078:227956] I'm in Loop
2016-02-02 17:11:16.227 facebookCustom Post[5078:227956] I'm in Loop
2016-02-02 17:11:16.227 facebookCustom Post[5078:227840] I'm in the second task of aQueue
2016-02-02 17:11:16.426 facebookCustom Post[5078:227840] I'm in main for the first time
2016-02-02 17:11:16.426 facebookCustom Post[5078:227840] I'm just about to exit from the main thread
代码的输出让我非常惊讶,因为在第一个任务完成之前不应该执行任务,因为我们是第一次同步调度队列,对吗?那怎么会在I'm in main for the first time
之前打印出I'm in the second task of aQueue
呢?
我相信在 this question 的答案中可以更完整地回答这个问题,并且与 GCD 实现中的优化有关。
作为优化,这些块正在当前(主)线程上执行,而不是在 aQueue
上执行,因此通过 dispatch_get_main_queue()
的任何调用都是 "queued up"(请原谅双关语)稍后执行,我认为在 运行-loop.
您可以通过使用 NSLog()
而不是 printf()
进行日志记录来获取更多信息,因为这将打印线程 ID。请使用该输出更新您的问题。
这就是我目前所知道的全部内容,也许@bbum 会路过并用更好的答案进行澄清。
顺便说一句,这是个好问题。
因为 printf 不需要在调用时准确地将字符显示在屏幕上。每个线程都可以收集 printf 输出,并在需要时将其显示在屏幕上。这通常更有效率。
在 printf 调用上设置断点,调用将按照您期望的顺序执行。 printf 不定义从多个线程调用时的输出顺序。
dispatch_sync
到 aQueue
阻塞了主线程,因此你的第一个 NSLog
到主线程被推迟到你的方法完成后 运行ning.
另外,你的做法是完全错误的。在大多数情况下,使用 dispatch_sync
从另一个串行队列到一个串行队列是完全多余的,因为在另一个串行队列完成之前,原始队列将被阻止运行。 它还有造成线程死锁的风险,因此您应该尽可能使用 dispatch_async
。
As said by this answer,当从主线程使用 dispatch_sync
到另一个串行队列时,在大多数情况下,GCD 只会在主线程上 运行 这个,因为传输很昂贵它。
但是我不确定您在这里使用 GCD 试图达到什么目的。您拥有的代码不比 运行 将所有内容都放在主线程上(因为这是最有可能在幕后发生的事情)。
如果您只是想将任务卸载到单独的线程上,那么您需要使用 dispatch_async
.
此外,如果您希望输出以可靠的顺序发生,您可以对主线程使用 dispatch_sync
(是的,我在这里对我的规则进行了例外处理,但只是因为它是单个 NSLog
),从而保证第一个主线程日志发生在下一个之前(并且不会导致死锁,因为您正在使用 dispatch_async
aQueue
).
-(void) sample
{
dispatch_queue_t aQueue = dispatch_queue_create("hello-world", DISPATCH_QUEUE_SERIAL); // I changed the attr parameter from NULL to DISPATCH_QUEUE_SERIAL for increased readability.
__block int j=0;
for(int i=0; i<3; ++i){
dispatch_async(aQueue, ^{
j++;
NSLog(@"I'm in Loop\n");
if(j==2)
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"I'm in main for the first time\n");
});
});
}
dispatch_async(aQueue, ^{
NSLog(@"I'm in the second task of aQueue\n");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"I'm just about to exit from the main thread\n");
});
});
}
现在的输出是:
2016-02-02 12:06:46.573 gcd test again[2351:2465744] I'm in Loop
2016-02-02 12:06:46.573 gcd test again[2351:2465744] I'm in Loop
2016-02-02 12:06:46.580 gcd test again[2351:2465707] I'm in main for the first time
2016-02-02 12:06:46.581 gcd test again[2351:2465744] I'm in Loop
2016-02-02 12:06:46.581 gcd test again[2351:2465744] I'm in the second task of aQueue
2016-02-02 12:06:46.581 gcd test again[2351:2465707] I'm just about to exit from the main thread
这样,主线程可以继续 运行,只是被打断以确保您的 NSLog
调用以正确的顺序分派。
但是,我绝不会推荐使用主队列“只是为了同步一些调用”。实际上,您应该为此使用一个单独的串行队列。
我希望这是有道理的。即使在最好的时候,GCD 也会令人困惑!