在主线程执行_主线程和主队列的关系

cda029b377d72f136c86b4de38513c89.png

作者 | 卡洛斯 
来源 | 卡洛斯的博客,点击阅读原文查看作者更多文章

先说结论

主队列只在主线程中被执行的,而主线程运行的是一个 runloop,不仅仅只有主队列的中的任务,还会处理 UI 的布局和绘制任务。

几个例子

一、自定义串行队列,同步执行。

- (void)someMethod {
dispatch_queue_t queue = dispatch_queue_create("com.kk", nil);
dispatch_sync(queue, ^{
NSLog(@"current thread = %@, curren queue = %@, main queue = %@", [NSThread currentThread], [NSString stringWithCString:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) encoding:NSUTF8StringEncoding], [NSString stringWithCString:dispatch_queue_get_label(dispatch_get_main_queue()) encoding:NSUTF8StringEncoding]);

});
}

------------------

current thread = <NSThread: 0x600002c0cf00>{number = 1, name = main}, curren queue = com.kk, main queue = com.apple.main-thread

这里是主线程但不是主队列。

二、主线程判断的几个方法

//下面这几种切换到主线程执行的方法, 你更喜欢哪种?有什么优缺点?
//方法1
if ([NSThread isMainThread]) {
//xxx
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
//xxx
});
}
// 如果是子线程执行这段代码,并且主队列里的任务是更新 UI,那么是会可能引起崩溃的。

//方法2
if ([NSThread isMainThread]) {
//xxx
} else {
dispatch_async(dispatch_get_main_queue(), ^{
//xxx
});
}
// 大部分都是这么用的,也没有什么问题
// 但是主线程不一定能过只跑主队列的任务。当主线程在同步执行自定义串行队列的任务时,那此方法的判断就不对了,因为此时是主线程且是非主队列

//方法3
dispatch_async(dispatch_get_main_queue(), ^{
//xxx
});
// 始终异步放在下一个loop使用,会延迟执行时机

//方法4
if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue())) {
//xxx
} else {
dispatch_async(dispatch_get_main_queue(), ^{
//xxx
});
}
// 方法二已经解释了,这里可以通过判断队列label的形式,可以保证任务一定是放在主队列中的。虽然方法二,也不会造成什么问题,但是方法四会更加符合预期(任务一定要在主队列中)

综合来说,方法 4 是更好的判断是否是主线程的方式。

苹果的一个bug

在苹果的MapKit框架中,有一个叫做addOverlay的方法,它在底层实现的时候,不仅仅要求代码执行在主线程上,还要求执行在 GCD 的主队列上。这是一个极罕见的问题,但已经有人在使用 ReactiveCocoa 时踩到了坑,并提交了 issue。

苹果的 Developer Technology Support 承认这是一个 bug。
https://toutiao.io/posts/535857/app_preview

正如上面的方法二,使用起来不会有什么问题,但是在这里,如果把一些数据通过dispatch_set_specific 绑定到main queue中,这才会产生 bug。例如下面,
这个获取就是和 main queue 绑定的,如果仅仅在主线程访问,无法获取到数据。

var skr = DispatchSpecificKey("")
if Thread.isMainThread {
let v = DispatchQueue.main.getSpecific(key: skr)
} else {
DispatchQueue.main.sync {
let v = DispatchQueue.main.getSpecific(key: skr)
}
}

参考

[1] http://sindrilin.com/2018/03/03/weird_thread.html 
[2] https://toutiao.io/posts/535857/app_preview

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
相对于主线程,JavaScript中的异步执行和同步执行顺序有所不同。在同步执行中,代码会按照顺序依次执行,每个操作都会等待前一个操作完成后再执行下一个操作。这意味着在同步执行中,主线程必须等待每个操作完成后才能继续执行下一个操作。这可能导致程序的执行效率较低。 而在异步执行中,当遇到耗时的操作时,主线程不会等待操作完成,而是会继续执行后续的操作。耗时的操作会被移交给其他线程或者Web APIs来处理,当操作完成后,会通过事件队将结果返回给主线程继续处理。因此,在异步执行中,主线程可以并行执行其他任务,不需要等待耗时操作的完成。 总结来说,相对于主线程,异步执行的顺序是不需要等待耗时操作的完成,可以继续执行后续的操作;而同步执行的顺序是需要等待每个操作的完成才能继续执行下一个操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [JS异步同步和EvenLoop单线程机制(一文读懂)](https://blog.csdn.net/qq_30386941/article/details/127550267)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值