| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8d3841d commit fc86e64
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -196,6 +196,78 @@ dispatch_suspend(queue); | |||
| 196 | 196 | dispatch_resume (source); | |
| 197 | 197 | ``` | |
| 198 | 198 | ||
| 199 | + 为了方便理解 `dispatch_suspend` 函数的作用,这里提供一个 Demo:Demo3, 看下运行效果: | ||
| 200 | + | ||
| 201 | + 思考下NSLog的打印顺序为什么会是这样? | ||
| 202 | + | ||
| 203 | + | ||
| 204 | + 详见 Demo3(Demo_03_对DispatchQueue实现取消恢复操作_简单版): | ||
| 205 | + | ||
| 206 | + | ||
| 207 | + ```Objective-C | ||
| 208 | + - (void)viewDidLoad { | ||
| 209 | + [super viewDidLoad]; | ||
| 210 | + | ||
| 211 | + dispatch_queue_t queue1 = dispatch_queue_create("com.iOSChengXuYuan.queue1", 0); | ||
| 212 | + dispatch_queue_t queue2 = dispatch_queue_create("com.iOSChengXuYuan.queue2", 0); | ||
| 213 | + dispatch_group_t group = dispatch_group_create(); | ||
| 214 | + | ||
| 215 | + dispatch_async(queue1, ^{ | ||
| 216 | + NSLog(@"任务 1 : queue 1..."); | ||
| 217 | + sleep(1); | ||
| 218 | + NSLog(@"✅完成任务 1"); | ||
| 219 | + }); | ||
| 220 | + | ||
| 221 | + dispatch_async(queue2, ^{ | ||
| 222 | + NSLog(@"任务 1 : queue 2..."); | ||
| 223 | + sleep(1); | ||
| 224 | + NSLog(@"✅完成任务 2"); | ||
| 225 | + }); | ||
| 226 | + | ||
| 227 | + dispatch_group_async(group, queue1, ^{ | ||
| 228 | + NSLog(@"🚫正在暂停 1"); | ||
| 229 | + dispatch_suspend(queue1); | ||
| 230 | + }); | ||
| 231 | + dispatch_group_async(group, queue2, ^{ | ||
| 232 | + NSLog(@"🚫正在暂停 2"); | ||
| 233 | + dispatch_suspend(queue2); | ||
| 234 | + }); | ||
| 235 | + | ||
| 236 | + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); | ||
| 237 | + NSLog(@"=======等待两个queue完成, 再往下进行..."); | ||
| 238 | + dispatch_async(queue1, ^{ | ||
| 239 | + NSLog(@"任务 2 : queue 1"); | ||
| 240 | + }); | ||
| 241 | + dispatch_async(queue2, ^{ | ||
| 242 | + NSLog(@"任务 2 : queue 2"); | ||
| 243 | + }); | ||
| 244 | + NSLog(@"🔴为什么这个NSLog会在上面两个NSLog之前打印❓❓答:dispatch_suspend的作用‼️"); | ||
| 245 | + | ||
| 246 | + dispatch_resume(queue1); | ||
| 247 | + dispatch_resume(queue2); | ||
| 248 | + } | ||
| 249 | + ``` | ||
| 250 | + | ||
| 251 | + 打印: | ||
| 252 | + | ||
| 253 | + ```Objective-C | ||
| 254 | + 2015-09-06 02:44:59.614 CYLDispatchQueueSuspendTest[1610:116662] 任务 1 : queue 2... | ||
| 255 | + 2015-09-06 02:44:59.613 CYLDispatchQueueSuspendTest[1610:116665] 任务 1 : queue 1... | ||
| 256 | + 2015-09-06 02:45:00.614 CYLDispatchQueueSuspendTest[1610:116665] ✅完成任务 1 | ||
| 257 | + 2015-09-06 02:45:00.614 CYLDispatchQueueSuspendTest[1610:116662] ✅完成任务 2 | ||
| 258 | + 2015-09-06 02:45:00.616 CYLDispatchQueueSuspendTest[1610:116662] 🚫正在暂停 2 | ||
| 259 | + 2015-09-06 02:45:00.615 CYLDispatchQueueSuspendTest[1610:116665] 🚫正在暂停 1 | ||
| 260 | + 2015-09-06 02:45:00.616 CYLDispatchQueueSuspendTest[1610:116515] =======等待两个queue完成, 再往下进行... | ||
| 261 | + 2015-09-06 02:45:00.616 CYLDispatchQueueSuspendTest[1610:116515] 🔴为什么这个NSLog会在上面两个NSLog之前打印❓❓答:dispatch_suspend的作用‼️ | ||
| 262 | + 2015-09-06 02:45:00.617 CYLDispatchQueueSuspendTest[1610:116665] 任务 2 : queue 1 | ||
| 263 | + 2015-09-06 02:45:00.619 CYLDispatchQueueSuspendTest[1610:116665] 任务 2 : queue 2 | ||
| 264 | + ``` | ||
| 265 | + | ||
| 266 | + 思考下NSLog的打印顺序为什么会是这样?答:dispatch_suspend的作用! | ||
| 267 | + | ||
| 268 | + 详见 Demo3(Demo_03_对DispatchQueue实现取消恢复操作_简单版)。 | ||
| 269 | + | ||
| 270 | + | ||
| 199 | 271 | ### 第四步:向`Dispatch Source`发送事件 | |
| 200 | 272 | ||
| 201 | 273 | 恢复源后,就可以像下面的代码片段这样,通过 `dispatch_source_merge_data` 向分派源发送事件: | |
@@ -518,6 +590,7 @@ dispatch_resume (source); | |||
| 518 | 590 | ||
| 519 | 591 | ### 让 Dispatch Source 与 Dispatch Queue 同时实现暂停和恢复 | |
| 520 | 592 | ||
| 593 | + 本节代码详见 Demo4(Demo_04_对DispatchQueue实现取消恢复操作_综合版) | ||
| 521 | 594 | ||
| 522 | 595 | 你可能已经发现了:上面的代码是有问题的,它只是一种“假暂停”的状态。for 循环还是要执行100变,循环的次数并没有你的暂停而暂停,这在实际开发中是不允许的,因为真正的性能瓶颈永远会是在这里,这样的暂停毫无意义。那么如何让 for 循环随时可以暂停? | |
| 523 | 596 | ||
@@ -624,7 +697,7 @@ dispatch_async(queue, ^{ | |||
| 624 | 697 | ``` | |
| 625 | 698 | ||
| 626 | 699 |  | |
| 627 | - | ||
| 700 | + 详见 Demo4(Demo_04_对DispatchQueue实现取消恢复操作_综合版) | ||
| 628 | 701 | ||
| 629 | 702 | ||
| 630 | 703 | ## Parse “离线存储对象”操作的代码摘录 | |
@@ -714,70 +787,6 @@ dispatch_async(queue, ^{ | |||
| 714 | 787 | ||
| 715 | 788 | 为了展示作用,举个反例: | |
| 716 | 789 | ||
| 717 | - 详见 Demo3(Demo_03_对DispatchQueue实现取消恢复操作_简单版): | ||
| 718 | - | ||
| 719 | - | ||
| 720 | - ```Objective-C | ||
| 721 | - - (void)viewDidLoad { | ||
| 722 | - [super viewDidLoad]; | ||
| 723 | - | ||
| 724 | - dispatch_queue_t queue1 = dispatch_queue_create("com.iOSChengXuYuan.queue1", 0); | ||
| 725 | - dispatch_queue_t queue2 = dispatch_queue_create("com.iOSChengXuYuan.queue2", 0); | ||
| 726 | - dispatch_group_t group = dispatch_group_create(); | ||
| 727 | - | ||
| 728 | - dispatch_async(queue1, ^{ | ||
| 729 | - NSLog(@"任务 1 : queue 1..."); | ||
| 730 | - sleep(1); | ||
| 731 | - NSLog(@"✅完成任务 1"); | ||
| 732 | - }); | ||
| 733 | - | ||
| 734 | - dispatch_async(queue2, ^{ | ||
| 735 | - NSLog(@"任务 1 : queue 2..."); | ||
| 736 | - sleep(1); | ||
| 737 | - NSLog(@"✅完成任务 2"); | ||
| 738 | - }); | ||
| 739 | - | ||
| 740 | - dispatch_group_async(group, queue1, ^{ | ||
| 741 | - NSLog(@"🚫正在暂停 1"); | ||
| 742 | - dispatch_suspend(queue1); | ||
| 743 | - }); | ||
| 744 | - dispatch_group_async(group, queue2, ^{ | ||
| 745 | - NSLog(@"🚫正在暂停 2"); | ||
| 746 | - dispatch_suspend(queue2); | ||
| 747 | - }); | ||
| 748 | - | ||
| 749 | - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); | ||
| 750 | - NSLog(@"=======等待两个queue完成, 再往下进行..."); | ||
| 751 | - dispatch_async(queue1, ^{ | ||
| 752 | - NSLog(@"任务 2 : queue 1"); | ||
| 753 | - }); | ||
| 754 | - dispatch_async(queue2, ^{ | ||
| 755 | - NSLog(@"任务 2 : queue 2"); | ||
| 756 | - }); | ||
| 757 | - NSLog(@"🔴为什么这个NSLog会在上面两个NSLog之前打印❓❓答:dispatch_suspend的作用‼️"); | ||
| 758 | - | ||
| 759 | - dispatch_resume(queue1); | ||
| 760 | - dispatch_resume(queue2); | ||
| 761 | - } | ||
| 762 | - ``` | ||
| 763 | - | ||
| 764 | - 打印: | ||
| 765 | - | ||
| 766 | - ```Objective-C | ||
| 767 | - 2015-09-06 02:44:59.614 CYLDispatchQueueSuspendTest[1610:116662] 任务 1 : queue 2... | ||
| 768 | - 2015-09-06 02:44:59.613 CYLDispatchQueueSuspendTest[1610:116665] 任务 1 : queue 1... | ||
| 769 | - 2015-09-06 02:45:00.614 CYLDispatchQueueSuspendTest[1610:116665] ✅完成任务 1 | ||
| 770 | - 2015-09-06 02:45:00.614 CYLDispatchQueueSuspendTest[1610:116662] ✅完成任务 2 | ||
| 771 | - 2015-09-06 02:45:00.616 CYLDispatchQueueSuspendTest[1610:116662] 🚫正在暂停 2 | ||
| 772 | - 2015-09-06 02:45:00.615 CYLDispatchQueueSuspendTest[1610:116665] 🚫正在暂停 1 | ||
| 773 | - 2015-09-06 02:45:00.616 CYLDispatchQueueSuspendTest[1610:116515] =======等待两个queue完成, 再往下进行... | ||
| 774 | - 2015-09-06 02:45:00.616 CYLDispatchQueueSuspendTest[1610:116515] 🔴为什么这个NSLog会在上面两个NSLog之前打印❓❓答:dispatch_suspend的作用‼️ | ||
| 775 | - 2015-09-06 02:45:00.617 CYLDispatchQueueSuspendTest[1610:116665] 任务 2 : queue 1 | ||
| 776 | - 2015-09-06 02:45:00.619 CYLDispatchQueueSuspendTest[1610:116665] 任务 2 : queue 2 | ||
| 777 | - ``` | ||
| 778 | - | ||
| 779 | - | ||
| 780 | - | ||
| 781 | 790 | ```Objective-C | |
| 782 | 791 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); | |
| 783 | 792 | NSMutableArray *array = [[NSMutableArray alloc] init]; | |
@@ -820,11 +829,10 @@ CYLDispatchSemaphoreTest(10384,0x112d43000) malloc: *** error for object 0x7f898 | |||
| 820 | 829 | 2015-09-07 00:42:52.734 CYLDispatchSemaphoreTest[10438:780505] 99949 | |
| 821 | 830 | ``` | |
| 822 | 831 | ||
| 823 | - | ||
| 832 | + 这种资源抢夺的情况,一般的做法是使用串行队列,或者像下面一样的同步队列,得以解决: | ||
| 824 | 833 | ||
| 825 | 834 | ```Objective-C | |
| 826 | 835 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); | |
| 827 | - dispatch_semaphore_t semaphore = dispatch_semaphore_create(1) ; | ||
| 828 | 836 | NSMutableArray *array = [[NSMutableArray alloc] init]; | |
| 829 | 837 | for(int i = 0; i< 100000; ++i) { | |
| 830 | 838 | dispatch_sync(queue, ^{ | |
@@ -834,7 +842,129 @@ CYLDispatchSemaphoreTest(10384,0x112d43000) malloc: *** error for object 0x7f898 | |||
| 834 | 842 | } | |
| 835 | 843 | NSLog(@"%@", @([array count])); | |
| 836 | 844 | ``` | |
| 837 | - 详见 Demo3(Demo_03_对DispatchQueue实现取消恢复操作_简单版): | ||
| 845 | + | ||
| 846 | + 下面展示下展示使用 `dispatch_semaphore_t` 的解决方案: | ||
| 847 | + | ||
| 848 | + | ||
| 849 | + | ||
| 850 | + `dispatch_semaphore_t` 的作用之一就是解决这种资源抢夺的情况,下面展示下使用 `dispatch_semaphore_t` 实现一个资源锁: | ||
| 851 | + | ||
| 852 | + 以下源码详见 Demo6(Demo_06_展示dispatch_semaphore_t基本用法) | ||
| 853 | + | ||
| 854 | + | ||
| 855 | + ```Objective-C | ||
| 856 | + - (void)viewDidLoad { | ||
| 857 | + [super viewDidLoad]; | ||
| 858 | + //因为用到了dispatch_barrier_async,该函数只能搭配自定义并行队列dispatch_queue_t使用。所以不能使用:dispatch_get_global_queue | ||
| 859 | + dispatch_queue_t queue = dispatch_queue_create("com.ioschengxuyuan.gcd.ForBarrier", DISPATCH_QUEUE_CONCURRENT); | ||
| 860 | + /* | ||
| 861 | + * | ||
| 862 | + *生成Dispatch Semaphore | ||
| 863 | + Dispatch Semaphore 的计数初始值设定为“1” | ||
| 864 | + (该初始值的1与下文中两个函数dispatch_semaphore_wait与dispatch_semaphore_signal进行的减1、加1里的1没有必然联系。 | ||
| 865 | + | ||
| 866 | + 就算初始值是100,两个函数dispatch_semaphore_wait与dispatch_semaphore_signal还是会减“1”、加“1”)。 | ||
| 867 | + 保证可访问 NSMutableArray 类对象的线程 | ||
| 868 | + 同时只能有1个 | ||
| 869 | + * | ||
| 870 | + */ | ||
| 871 | + dispatch_semaphore_t semaphore = dispatch_semaphore_create(1) ; | ||
| 872 | + NSMutableArray *array = [[NSMutableArray alloc] init]; | ||
| 873 | + for(int i = 0; i< 100000; ++i) { | ||
| 874 | + dispatch_async(queue, ^{ | ||
| 875 | + /* | ||
| 876 | + * | ||
| 877 | + *等待Dispatch Semaphore | ||
| 878 | + *一直等待,直到Dispatch Semaphore的计数值达到大于等于1 | ||
| 879 | + */ | ||
| 880 | + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) ; | ||
| 881 | + /* | ||
| 882 | + *由于Dispatch Semaphore的计数值达到大于等于1 | ||
| 883 | + *所以将Dispatch Semaphore的计数值减去1 | ||
| 884 | + *dispatch_semaphore_wait 函数执行返回。 | ||
| 885 | + *即执行到此时的 | ||
| 886 | + *Dispatch Semaphore 的计数值恒为0 | ||
| 887 | + * | ||
| 888 | + *由于可访问NSMutaleArray类对象的线程 | ||
| 889 | + *只有一个 | ||
| 890 | + *因此可安全地进行更新 | ||
| 891 | + * | ||
| 892 | + */ | ||
| 893 | + NSLog(@"🔴%@",[NSThread currentThread]); | ||
| 894 | + [array addObject:[NSNumber numberWithInt:i]]; | ||
| 895 | + /* | ||
| 896 | + * | ||
| 897 | + *排他控制处理结束, | ||
| 898 | + *所以通过dispatch_semaphore_signal函数 | ||
| 899 | + *将Dispatch Semaphore的计数值加1 | ||
| 900 | + *如果有通过dispatch_semaphore_wait函数 | ||
| 901 | + *等待Dispatch Semaphore的计数值增加的线程, | ||
| 902 | + ★就由最先等待的线程执行。 | ||
| 903 | + */ | ||
| 904 | + dispatch_semaphore_signal(semaphore); | ||
| 905 | + }); | ||
| 906 | + } | ||
| 907 | + /* | ||
| 908 | + * | ||
| 909 | + 等为数组遍历添加元素后,检查下数组的成员个数是否正确 | ||
| 910 | + * | ||
| 911 | + */ | ||
| 912 | + dispatch_barrier_async(queue, ^{ | ||
| 913 | + NSLog(@"🔴类名与方法名:%s(在第%d行),描述:%@", __PRETTY_FUNCTION__, __LINE__, @([array count])); | ||
| 914 | + }); | ||
| 915 | + } | ||
| 916 | + ``` | ||
| 917 | + | ||
| 918 | + | ||
| 919 | + | ||
| 920 | + | ||
| 921 | + 详见 Demo5(Demo_05_展示dispatch_semaphore_t基本用法) | ||
| 922 | + | ||
| 923 | + ```Objective-C | ||
| 924 | + - (void)viewDidLoad { | ||
| 925 | + [super viewDidLoad]; | ||
| 926 | + | ||
| 927 | + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); | ||
| 928 | + // dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); | ||
| 929 | + | ||
| 930 | + dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);//等待一秒 | ||
| 931 | + //dispatch_time_t time = DISPATCH_TIME_FOREVER;//永久等待 | ||
| 932 | + NSLog(@"begin ==> 车库开始营业了!"); | ||
| 933 | + /* | ||
| 934 | + * | ||
| 935 | + 如果 semphore 的值等于0,就阻塞1秒钟,才会往下照常进行; | ||
| 936 | + 如果大于等于1则往下进行并将 semphore 进行减1处理。 | ||
| 937 | + * | ||
| 938 | + */ | ||
| 939 | + long result = dispatch_semaphore_wait(semaphore, time); | ||
| 940 | + if (result == 0) { | ||
| 941 | + /* | ||
| 942 | + * | ||
| 943 | + *由子Dispatch Semaphore的计数值达到大于等于1 | ||
| 944 | + *或者在待机中的指定时间内 | ||
| 945 | + *Dispatch Semaphore的计数值达到大于等于1 | ||
| 946 | + 所以Dispatch Semaphore的计数值减去1 | ||
| 947 | + 可执行需要进行排他控制的处理. | ||
| 948 | + 可以理解为:没有阻塞的线程了。 | ||
| 949 | + 就好比:车库有一个或一个以上的车位,只来了一辆车,所以“无需等待” | ||
| 950 | + * | ||
| 951 | + */ | ||
| 952 | + NSLog(@"result = 0 ==> 有车位,无需等待!==> 在这里可安全地执行【需要排他控制的处理(比如只允许一条线程为mutableArray进行addObj操作)】"); | ||
| 953 | + dispatch_semaphore_signal(semaphore);//使用signal以确保编译器release掉dispatch_semaphore_t时的值与初始值一致, 否则会EXC_BAD_INSTRUCTION ,见http://is.gd/EaJgk5 | ||
| 954 | + } else { | ||
| 955 | + /* | ||
| 956 | + * | ||
| 957 | + *由于Dispatch Semaphore的计数值为0 | ||
| 958 | + .因此在达到指定时间为止待机 | ||
| 959 | + 这个else里发生的事情,就好比:车库没车位,来了一辆车,等待了半个小时后,做出的一些事情。 | ||
| 960 | + 比如:忍受不了,走了。。 | ||
| 961 | + * | ||
| 962 | + */ | ||
| 963 | + NSLog(@"result != 0 ==> timeout,deadline,忍受不了,走了。。"); | ||
| 964 | + | ||
| 965 | + } | ||
| 966 | + } | ||
| 967 | + ``` | ||
| 838 | 968 | ||
| 839 | 969 | ||
| 840 | 970 | ### 在项目中的应用:强制把异步任务转换为同步任务来方便进行单元测试 | |
@@ -899,6 +1029,7 @@ CYLDispatchSemaphoreTest(10384,0x112d43000) malloc: *** error for object 0x7f898 | |||
| 899 | 1029 | 耐心的极限时间 | 超时时间 | `dispatch_semaphore_wait` | | |
| 900 | 1030 | 逛街结束走了,离开车位 | signal+1 | `dispatch_semaphore_signal` | | |
| 901 | 1031 | ||
| 1032 | + | ||
| 902 | 1033 | ### 使用`Dispatch Semaphore`控制并发线程数量 | |
| 903 | 1034 | ||
| 904 | 1035 | 正如文章开头所说:从 iOS7 升到 iOS8 后,GCD 出现了一个重大的变化:在 iOS7 时,使用 GCD 的并行队列, `dispatch_async` 最大开启的线程一直能控制在6、7条,线程数都是个位数,然而 iOS8后,最大线程数一度可以达到40条、50条。然而在文档上并没有对这一做法的目的进行介绍。 | |
| Back | FazBrowse Home | New Git URL |
0 commit comments