- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我读到的评论是,将队列分派(dispatch)到主线程与在主线程上执行代码不同。如果我理解正确的话,用户是这么说的
dispatch_async(dispatch_get_main_queue(),
^{
// some code
});
和这个不一样
[self performSelectorOnMainThread:@selector(doStuff)
withObject:nil waitUntilDone:NO];
- (void) doStuff {
// some code
}
此评论是否属实?
排除第一个代码是异步的这一事实,对我来说,两个代码在主线程上同等执行。它们之间有技术上的区别吗?
我这么问是因为我有一些代码在主线程上使用dispatch_async更新UI,但它不起作用,但是当我使用performSelectorOnMainThread将其更改为第二种形式时,它起作用了。
最佳答案
是的,有区别。主调度队列是串行队列。这意味着,当它运行已提交给它的任务时,它无法运行任何其他任务。即使它运行内部事件循环也是如此。
-performSelectorOnMainThread:...
通过运行循环源进行操作。运行循环源可以在内部运行循环中触发,即使该内部运行循环是先前触发同一源的结果。
其中一个例子是运行模式文件打开对话框。 (非沙盒化,因此对话框处于进程中。)我从提交到主调度队列的任务启动了模式对话框。事实证明,打开对话框的内部实现也异步地将一些工作分派(dispatch)到主队列。由于主调度队列被运行对话框的任务占用,因此直到对话框完成后它才处理框架的任务。症状是对话框将无法显示文件,直到某个内部超时(大约一分钟左右)到期。
请注意,这不是由主线程向主队列发出同步请求导致的死锁,尽管这种情况也可能发生。使用GCD,这样的同步请求肯定会死锁。与-performSelectorOnMainThread:...
,它不会,因为同步请求( waitUntilDone
设置为 YES
)只是直接运行。
顺便说一下,您说“第一个代码是异步的”,好像是为了与第二个代码进行对比。两者都是异步的,因为您传递了 NO
对于 waitUntilDone
在第二个。
更新:
考虑这样的代码:
dispatch_async(dispatch_get_main_queue(), ^{
printf("outer task, milestone 1\n");
dispatch_async(dispatch_get_main_queue(), ^{
printf("inner task\n");
});
// Although running the run loop directly like this is uncommon, this simulates what
// happens if you do something like run a modal dialog or call -[NSTask waitUntilExit].
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
printf("outer task, milestone 2\n");
});
这将记录:
outer task, milestone 1
outer task, milestone 2
inner task
在外部任务完成之前,内部任务不会运行。即使外部任务运行主运行循环(处理调度到主队列的任务),情况也是如此。原因是主队列是串行队列,在运行任务时永远不会启动新任务。
如果改变内部dispatch_async()
至dispatch_sync()
,那么程序就会死锁。
相比之下,请考虑:
- (void) task2
{
printf("task2\n");
}
- (void) task1
{
printf("task1 milestone 1\n");
[self performSelectorOnMainThread:@selector(task2) withObject:nil waitUntilDone:NO];
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
printf("task1 milestone 2\n");
}
(... in some other method:)
[self performSelectorOnMainThread:@selector(task1) withObject:nil waitUntilDone:NO];
这将记录:
task1 milestone 1
task2
task1 milestone 2
在 -task1
内运行运行循环给内心一个机会-performSelectorOnMainThread:...
运行。这是两种技术之间的巨大区别。
如果您更改NO
至YES
在-task1
,这仍然有效,没有死锁。这是另一个区别。那是因为,当 -performSelectorOnMainThread:...
被调用 waitUntilDone
设置为 true,它会检查是否在主线程上调用。如果是,那么它就直接调用那里的选择器。就好像这只是一个对 -performSelector:withObject:
的调用。 .
关于multithreading - GCD主队列和主线程有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23856230/
我是一名优秀的程序员,十分优秀!