听故事学iOS系列 - 屎壳郎老板和它的收费公厕(一个故事搞懂多
刚接触开发的童鞋,在学习多线程的时候,往往会比较吃力.因为这家伙比较抽象,有的时候较难通过运行代码直接看到多线程操作应该有的实际效果.和UI相比,多线程部分更注重理解.
所以,希望能通过这个故事,帮助大家更好地理解iOS中的多线程.故事是以GCD为主要实现手段进行展开的.
OK,那废话不多说,一起走进财富故事汇之屎壳郎老板的公厕生意吧!
屎壳郎老板和它的公厕生意
屎壳郎老板在旅游区开了一间收费公厕,招待南来北往的旅客们。来上厕所的客人,都是跟着各自的旅行团来的。屎壳郎老板要求上厕所的客人一定要排好队,一个一个来,讲文明,懂礼貌,谢绝插队和随地大小便等不文明行为。
奇葩的旅客、奇葩的团
屎壳郎老板发现,来它这里上厕所的旅客,都非常怪异:
明明坑位很多,排队的人也很多,可是有的时候只有一个坑位被使用,有的时候同时有好多坑位被使用。
为了弄清楚坑位的使用规律,屎壳郎老板对来上厕所的旅客,和他们所在的旅行团进行了调查统计分析。
-- 旅客篇 --
根据旅客的尿意程度,屎壳郎老板把旅客分为两类:
- 尿急型
- 有备无患型
尿急型旅客
- 一旦前面的坑位没人,这类旅客就会一头扎进坑位中。
通过数据分析,屎壳郎老板还发现:
- 尿急型旅客只认准靠窗的蹲位,别的蹲位一概不去。
有备无患型旅客
这类旅客其实不是很急着上厕所,他们只是看到排队上厕所的人多,想通过排队等坑位的时间,来拓展自己的人脉圈的(如此高明的拓展人脉圈手段也是醉了-_-|||)
轮到他们进坑的时候,他们不会一头扎进去,而是
- 先勾搭他后面的旅客
“嘿哥们儿,一起啊~”
看到后面的哥们准备动身了,他才动身
屎壳郎老板还发现,这类旅客:
- 一般会尽最大可能不用靠窗的坑位。
附注
由于尿急型旅客不主动招呼排在他后面的旅客,所以,后面的旅客只有亲眼看到尿急旅客已经方便完从坑位出来了,才会选坑进入。
-- 旅行团篇 --
研究完旅客,屎壳郎老板又对旅客们所在的旅行团做了分析和归类。根据旅行团印发的《关于参团游客排队上公厕秩序的相关规定》内容进行划分(这旅行团管的也太宽了吧-_-|||),大致可以分为三大类
- 宽松型
- 严格型
- 苛刻型
宽松型
团规:团内旅客尽量用最短的时间解决完上厕所问题,使用哪个坑位不做限制。
严格型
团规:不管有没有空余的坑位,本团内,一次只能有一个旅客在坑位上。
苛刻型
团规:本团内的旅客,只能使用靠窗的那个坑位。
屎壳郎老板很开心,因为有了这两份资料,他就能提前判断出,下一次,会有几个旅客同时进坑,以及他们分别会用几号坑位。
屎壳郎老板的测试题
OK,屎壳郎老板收集到的情报我们已经掌握了,那么,屎壳郎老板给大家出了一份测试题,我们一起来试着分析下吧!
题目:
假设这次排队的旅客有四个:
其中 三个来自名叫“严格旅行团”的严格型旅行团
另外两个来自名叫“宽松旅行团”的宽松型团
根据从前到后的顺序,他们分别是:
* 小A同学:来自宽松团,有备无患型
* 小B同学:来自宽松团,有备无患型
* 小C同学:来自严格团,尿急型
* 小D同学:来自宽松团,有备无患型
* 小E同学:来自严格团,尿急型
模拟入坑过程
第一阶段
- 轮到排在最前面的小 A 同学入坑了,由于小 A是个有备无患型的,扭过头来招呼小 B:“嘿哥们儿一起啊”
- 小 B 同学也兴奋的扭过头招呼小 C:" 嘿哥们,一起啊~"
- 小 C 已经憋很久了,拔腿就准备往蹲位里冲。
- 小 B 看到小 C 准备动身了,自己也整理整理准备动身。
- 小 A 看小 B 准备动身了,自己马上动身走向坑位。因为是有备无患型,所以小 A 讨厌靠窗的1号蹲位,选择了2号蹲位。
- 小 B 动身前也思考了一下,我们团允许多个团员同时入坑。于是小 B 也动身了。有备无患型,讨厌靠窗的1号蹲位,2号蹲位又有人了,于是选择了3号蹲位
- 虽然便意浓浓,但小 C 还是略一思忖:我们团规定一次只能一个人入坑,前面入坑的两个都不是我们团的,看来我能入坑。然后看了一眼坑位:我喜欢的靠窗1号坑正好没人用!然后拔腿奔向了1号坑位。
总结:第一阶段同时入坑的有ABC三 位同学,分别使用了2号坑、3号坑和1号坑
第二阶段
- 亲眼看见小 C 从蹲位里面带幸福的走出来,小 D 知道,轮到自己了。于是招呼小 E 一起入坑
- 小 E 二话不说低着头就准备往坑里冲。小 D 见状略一思忖:我们团允许多个本团成员一起入坑,虽然之前两个团员小 A 和小 B 还没出来(假设小 A 和小B 解决的比较慢),但我还是可以入坑的。 于是动身选坑位
- 1号坑位虽然没人,但是小 D不喜欢,2号3号有人了(小 A 小 B 在里面),所以小 D 选择了4号坑位
- 小 E 临行前也简单思考了下:我们团没有人在蹲位中,1号蹲位没有人。于是小 E 冲向了1号蹲位。
总结:第二阶段同时入坑的有 DE 两位同学,分别使用了4号坑和1号坑。
验证
OK分析完成,我们用代码来验证下是不是这样
代码们
屎壳郎老板的测试题 - 代码验证.png可以尝试自己运行下看看结果是不是和我们分析的一样哦!
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 创建名叫“严格旅行团”的严格型旅行团
dispatch_queue_t seriouslyTeam = dispatch_queue_create("com.azen.xu", DISPATCH_QUEUE_SERIAL);
// 创建名叫“宽松旅行团”的宽松型旅行团
dispatch_queue_t relaxingTeam = dispatch_queue_create("com.azen.xu",DISPATCH_QUEUE_CONCURRENT);
// 创建宽松团的有备无患型小 A
dispatch_async( relaxingTeam, ^{
// 让小 A 便便的时间长一点
for (int i = 0 ; i <= 1000 ; i++)
{
NSLog(@"我是小 A,我在便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]);
}
});
// 创建与小 A 相似的小 B
dispatch_async( relaxingTeam, ^{
// 让小 B 便便的时间也长一点
for (int i = 0 ; i <= 1000 ; i++)
{
NSLog(@"我是小 B,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]);
}
});
// 创建严格团的尿急小 C
dispatch_sync(seriouslyTeam, ^{
// 小 C 便的时间短一点
for (int i = 0 ; i <= 10 ; i++)
{
NSLog(@"我是小 C,我在也便便 -- 完成度 %%%d ---%@",i * 10,[NSThread currentThread]);
}
});
// 宽松团的有备无患型小 D
dispatch_async( relaxingTeam, ^{
// 让小 D 便便的时间也长一点
for (int i = 0 ; i <= 1000 ; i++)
{
NSLog(@"我是小 D,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]);
}
});
// 严格团的尿急小 E
dispatch_sync( seriouslyTeam, ^{
// 让小 E 便便的时间也长一点
for (int i = 0 ; i <= 1000 ; i++)
{
NSLog(@"我是小 E,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]);
}
});
}
总结
嗯哼~ 故事讲完了。没看明白?不知道这鬼东西有什么卵用?不妨看看下面的对照表哦:
概念对照表
- 旅客 对应 任务
1.1 尿急型旅客 对应 同步任务
1.2 有备无患型旅客 对应 异步任务 - 旅行团 对应 队列
2.1 宽松型旅行团 对应 并发队列(Concurrent
Dispatch Queue)
2.2 严格型旅行团 对应 串行队列(Serial
Dispatch Queue)
2.3 苛刻型旅行团 对应 主队列(Main Queue) - 蹲位 对应 线程
3.1 靠窗蹲位 对应 主线程
(所有涉及 UI 展示方面的任务都要在主线程中执行,所以... 主线程就是靠窗的蹲位啦...)
3.2 其他蹲位 对应 子线程
应用
尝试用多线程知识实现:分 六个任务别打印A、B、C、D、E 、F 六个字母,要求:A打印完后打印 B 和 C(要求BC几乎同时打印),C 打印完后打印D、E、F( DEF几乎同时打印)
最后的最后
一个故事并不能将多线程的知识完全讲清楚,只是希望,这篇小小的、有点怪诞、槽点满满的故事,能带给大家一点轻松快乐的好心情。会心一笑,然后带着这份好心情,一起继续在这个充满魔法的编程世界里前行吧~ _
PS. 刚编出来这个故事时候,每次上厕所看到蹲位都忍不住想笑... 不过想到边排泄边傻笑可能有点怪怪的...所以还是忍住了= =
PPS. 屎壳郎老板的故事还没有结束哦!下一篇——《屎壳郎老板的神奇宝贝——蹲位兽》,和大家一起探秘屎壳郎老板公厕的蹲位,顺便聊一点runloop的小知识_