gpt4 book ai didi

multithreading - GCD主队列和主线程有什么区别?

转载 作者:行者123 更新时间:2023-12-03 16:04:27 24 4
gpt4 key购买 nike

我读到的评论是,将队列分派(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:...运行。这是两种技术之间的巨大区别。

如果您更改NOYES-task1 ,这仍然有效,没有死锁。这是另一个区别。那是因为,当 -performSelectorOnMainThread:...被调用 waitUntilDone设置为 true,它会检查是否在主线程上调用。如果是,那么它就直接调用那里的选择器。就好像这只是一个对 -performSelector:withObject: 的调用。 .

关于multithreading - GCD主队列和主线程有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23856230/

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