runloop之于thread
做一个技术方向久了,难免会沉溺其中,对当初开始接触这个方向的许多根本上的疑问渐渐都不了了之,意识上认为然,而不知其所以然。
最近重新梳理iOS的runloop,说说自己的理解,希望能说清楚。
先抛出一个问题:程序入口main函数只是一段代码,为什么只运行了一段代码,程序就可以一直运行?
main函数中起了一个main thread,main thread执行结束,则应用程序退出,为了能让线程一直运行,苹果引入了runloop,苹果这样介绍runloop:
Run loops are part of the fundamental infrastructure associated with threads. A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none.
main thread中的runloop一直在跑圈圈(while循环),所以这个main thread不会立即执行结束,如果设定这个runloop跑圈的时间是1年,app就可以运行1年,1年后app自动退出。
这里面有两个问题:
- runloop如果一直在跑圈,会一直占用/消耗系统资源,怎么避免?
- 跑圈圈的同时,如果用户有输入等操作,怎么检测?
runloop是基于事件处理的,有事件需要处理,则runlopp开始跑圈检测需要处理的事件,处理结束后,进入休眠,当再次有事件需要处理时,再次被唤醒去跑圈,如此反复。
怎么知道有事件要去处理呢?事件包括许多,计时器、用户输入、点击、网络请求等,main thread中创建main runloop时,会将这些事件作为source加入到runloop中,这样,当其中一个source有变更时,激活runloop去跑圈。当然如果这些runloop中source都被移除了,runloop跑一圈之后就会被释放,线程也随即结束。如果main runloop的source可以全部移除,那就意味着app要退出了,但实际的情况是,main runloop被系统做了特殊处理,是无法真正把source都remove掉的,想通过移除source达到app exit的目的是不行的。
做移动开发的同学经常会被问到iOS系统为什么比Android系统流畅的问题,问题也出在runloop中。runloop中有几种模式,其中一种叫Event tracking模式,意为事件追踪,当用户滚动页面等操作时,runloop会被切换到追踪模式,这个模式会限制后续其他事件,比如在这个模式下,点击、长按等其他事件等都将会被限制,让系统只专注处理当前tracking的事件。整个系统只专注做一件事,当让流畅。
题为runloop之于thread,是说它们之间的关系,thread可以没有runloop,但runloop必须运行在线程中,也就是是apple说的The purpose of a run loop is to keep your thread busy 。thread和runloop是一一对应的,以键值对存储在底层,一个thread/runloop中可以嵌套多个thread/runloop。
iOS中非常著名的网络库AFNetworking(老版本,大家都喜欢拿这段代码进行解读)有这样一段代码:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
这段代码创建了一个守护线程,为了让这个线程能够一直在后台处理网络,在线程入口networkRequestThreadEntryPoint: 中通过 [NSRunLoop currentRunLoop]创建了一个runloop;为了runloop能够一直跑圈,向runloop中加入了一个Mach port源,只要这个port源不移除,runloop就会一直存在。
这个时候的runloop其实是一直处于休眠状态,随后开始网络请求时向其中加入了connection源:
- (void)operationDidStart {
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for (NSString *runLoopMode in self.runLoopModes) {
[self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
}
[self.connection start];
}
}
connection收到网络响应后,runloop被激活,开始跑圈,然后检测到有网络响应数据,runloop和connection协调数据输出,以回调的形式将底层接收的数据抛出,
当所有数据传输结束后,connection被AFNetworking置为ni,从runloop中移除,这时runloop进入休眠,这样就完成了一次在后台发请求、接收数据的过程。
等重新开始一次网络请求时,这个过程将会被再次执行一遍。
参考资料
Threading Programming Guide: Run Loops
Threading Programming Guide: Thread Management
runloop之于thread的更多相关文章
- 深入理解RunLoop
网上看的一篇文章,写的真好,我得多看几次好好理解理解 膜拜大神,转载至此便于学习查看. 此处标明原文链接:http://blog.ibireme.com/2015/05/18/runloop/ ...
- 【转】Thread.isBackground
C#中,Thread类有一个IsBackground 的属性.MSDN上对它的解释是:获取或设置一个值,该值指示某个线程是否为后台线程.个人感觉这样的解释等于没有解释. .Net中的线程,可以分为后台 ...
- 浅谈Runloop
RunLoop 是 iOS 和 OS X 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何 ...
- Runloop 深入理解(转)
RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何利 ...
- RunLoop的深入了解
RunLoop 是 iOS 和 OS X 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何 ...
- 关于Thread.IsBackground属性的理解(转载)
C#中,Thread类有一个IsBackground 的属性.MSDN上对它的解释是:获取或设置一个值,该值指示某个线程是否为后台线程.个人感觉这样的解释等于没有解释. .Net中的线程,可以分为后台 ...
- 史上最全的RunLoop介绍
之前有人在后台给小编留言,说:小编啥时候给我们分享RunLoop的一些文章,工作以后特别需要这样的技术.这不,小编从网上找了一个介绍非常详细,清晰的文章,仅供参考. RunLoop 是 iOS 和 O ...
- Thread IsBcakgroud
C#中,Thread类有一个IsBackground 的属性.MSDN上对它的解释是:获取或设置一个值,该值指示某个线程是否为后台线程.个人感觉这样的解释等于没有解释. .Net中的线程,可以分为后台 ...
- iOS 深入理解RunLoop
RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何利 ...
随机推荐
- class0513(html)
精通DIV+CSS Meta 1.div span 2.三种样式表 内联样式(行内样式) 嵌入样式 外部样式 就近原则 3.常见样式 复合样式background border css单位 % px ...
- curl命令学习(转载的)
原文地址: http://www.thegeekstuff.com/2012/04/curl-examples/ curl是网络上常用一个命令,简单来说就是可以上传下载,甚至可以当成下载工具使用,比如 ...
- uvalive 4589 Asteroids
题意:给两个凸包,凸包能旋转,求凸包重心之间的最短距离. 思路:显然两个凸包贴在一起时,距离最短.所以,先求重心,再求重心到各个面的最短距离. 三维凸包+重心求法 重心求法:在凸包内,任意枚举一点,在 ...
- 50道经典的JAVA编程题 (1-5)
后天java考试,现在闲着也是闲着,来做做java题吧. 前不久在网上看见了50道java算法编程题,感觉还不错,记得大一学C语言的时候做过一些,现在用java来回顾下吧,也算应付考试吧. 代码要是有 ...
- 怎么创建MongoDB数据库
MongoDB didn’t provides any command to create “database“. Actually, you don’t need to create it manu ...
- Java内存管理原理及内存区域详解
一.概述 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间.Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如下 ...
- hdu 1877 又一版 A+B
又一版 A+B Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- SQL连接查询的方式
网上copy,以后来完整 连接条件可在FROM或WHERE子句中指定,建议在FROM子句中指定连接条件.WHERE和HAVING子句也可以包含搜索条件,以进一步筛选连接条件所选的行. ...
- PowerDesigner实用技巧小结(4)
下述十四个技巧,是许多人在大量的数据库分析与设计实践中,逐步总结出来的.对于这些经验的运用,读者不能生帮硬套,死记硬背,而要消化理解,实事求是,灵活掌握.并逐步做到:在应用中发展,在发展中应用. 1. ...
- session和request的区别
request 请求对象 请求中保存请求过程中需要的参数 比如另一个页面需要使用的对象编号,list,map等,请求结束,就失效了 session 会话对象 除非关闭会话(到时间通常为30分钟,或者关 ...