如何处理多个网络请求的并发的情况

一、概念

1.并发 当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。

2.并行 当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

3.区别 并发和并行是即相似又有区别的两个概念,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。

举个栗子

1).并发 一个送外卖的A需要把两份外卖分别送到两个客户B和C手里。 A必须先送完B外卖才能接着送C的。这就是并发

2).并行 客户C 分别从饿了么和美团订了一共两份外卖。那么外卖员A和外卖员B需要把外卖一同送到客户C手里。 这就是并行

  在iOS中,经常可以看见有这样的需求,就是一个方法要等另外一个方法执行完毕再做相对应的处理,比如说一些网络请求,需要根据上一个请求的返回值做相对应的处理再执行第二个请求,所以我们不能让两个请求同时去请求网络。下面就记录以下通过GCD和NSOperationQueue来控制并发。

二、代码部分(GCD)

dispatch_semaphore  信号量
 
  信号量是一个整型值并且具有初始计数值,信号量通常支持两个操作:通知和等待。当信号被通知的时候计数值会增加,当信号量在线程上等待的时候,必要的情况下线程会被阻塞掉,直至信号被通知时计数值大于0,然后线程会减少这个计数继续工作。
 
GCD中又3个信号量有关的操作:
 
dispatch_semaphore_create    信号量创建
 
dispatch_semaphore_signal    发送通知
 
dispatch_semaphore_wait     信号量等待

GCD

 1 #import <Foundation/Foundation.h>
2
3 int main(int argc, const char * argv[]) {
4
5 @autoreleasepool {
6
7 // 创建信号量
8
9 __block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
10
11 // 创建队列
12
13 dispatch_queue_t queue = dispatch_queue_create("testBlock", NULL);
14
15 dispatch_async(queue, ^{
16
17 for (int i = 0; i<10; i++) {
18
19 NSLog(@"i的值是:%d",i);
20
21 }
22
23 // 发送通知
24
25 dispatch_semaphore_signal(sem);
26
27 });
28
29
30
31 // 信号量等待
32
33 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
34
35
36
37 for (int j = 0; j<20; j++) {
38
39 NSLog(@"j的值是:%d",j);
40
41 }
42
43 }
44
45 return 0;
46
47 }

打印结果为

2015-07-28 16:17:04.195 多线程[16370:1833932] i的值是:0

2015-07-28 16:17:04.197 多线程[16370:1833932] i的值是:1

2015-07-28 16:17:04.197 多线程[16370:1833932] i的值是:2

2015-07-28 16:17:04.197 多线程[16370:1833932] i的值是:3

2015-07-28 16:17:04.197 多线程[16370:1833932] i的值是:4

2015-07-28 16:17:04.198 多线程[16370:1833932] i的值是:5

2015-07-28 16:17:04.198 多线程[16370:1833932] i的值是:6

2015-07-28 16:17:04.198 多线程[16370:1833932] i的值是:7

2015-07-28 16:17:04.198 多线程[16370:1833932] i的值是:8

2015-07-28 16:17:04.198 多线程[16370:1833932] i的值是:9

2015-07-28 16:17:04.198 多线程[16370:1833932] j的值是:0

2015-07-28 16:17:04.199 多线程[16370:1833932] j的值是:1

2015-07-28 16:17:04.199 多线程[16370:1833932] j的值是:2

2015-07-28 16:17:04.199 多线程[16370:1833932] j的值是:3

2015-07-28 16:17:04.199 多线程[16370:1833932] j的值是:4

2015-07-28 16:17:04.199 多线程[16370:1833932] j的值是:5

2015-07-28 16:17:04.199 多线程[16370:1833932] j的值是:6

2015-07-28 16:17:04.199 多线程[16370:1833932] j的值是:7

2015-07-28 16:17:04.221 多线程[16370:1833932] j的值是:8

2015-07-28 16:17:04.221 多线程[16370:1833932] j的值是:9

2015-07-28 16:17:04.222 多线程[16370:1833932] j的值是:10

2015-07-28 16:17:04.222 多线程[16370:1833932] j的值是:11

2015-07-28 16:17:04.222 多线程[16370:1833932] j的值是:12

2015-07-28 16:17:04.222 多线程[16370:1833932] j的值是:13

2015-07-28 16:17:04.222 多线程[16370:1833932] j的值是:14

2015-07-28 16:17:04.222 多线程[16370:1833932] j的值是:15

2015-07-28 16:17:04.222 多线程[16370:1833932] j的值是:16

2015-07-28 16:17:04.223 多线程[16370:1833932] j的值是:17

2015-07-28 16:17:04.223 多线程[16370:1833932] j的值是:18

2015-07-28 16:17:04.223 多线程[16370:1833932] j的值是:19

 我们看到先打印完i值后在打印j值 这就完成了并发请求

NSOperationQueue

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    // 创建一个队列

    NSOperationQueue *queue = [[NSOperationQueue alloc]init]; 

    // 设置最大线程数

    queue.maxConcurrentOperationCount = 5;

    // 创建一个A操作

    NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{

        for (int i = 0; i<10; i++) {
NSLog(@"i的值是:%d",i);
}
}]; // 创建一个B操作 NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{ for (int j = 0; j<20; j++) { NSLog(@"j的值是:%d",j); } }]; // 分别加入到队列中 [queue addOperation:operationA]; [queue addOperation:operationB]; }

打印结果

2015-07-28 17:51:09.508 111[16598:1880752] j的值是:0

2015-07-28 17:51:09.508 111[16598:1880750] i的值是:0

2015-07-28 17:51:09.509 111[16598:1880752] j的值是:1

2015-07-28 17:51:09.509 111[16598:1880750] i的值是:1

2015-07-28 17:51:09.509 111[16598:1880752] j的值是:2

2015-07-28 17:51:09.509 111[16598:1880750] i的值是:2

2015-07-28 17:51:09.509 111[16598:1880752] j的值是:3

2015-07-28 17:51:09.509 111[16598:1880750] i的值是:3

2015-07-28 17:51:09.509 111[16598:1880752] j的值是:4

2015-07-28 17:51:09.509 111[16598:1880750] i的值是:4

2015-07-28 17:51:09.509 111[16598:1880752] j的值是:5

2015-07-28 17:51:09.509 111[16598:1880750] i的值是:5

2015-07-28 17:51:09.509 111[16598:1880752] j的值是:6

2015-07-28 17:51:09.509 111[16598:1880750] i的值是:6

2015-07-28 17:51:09.509 111[16598:1880752] j的值是:7

2015-07-28 17:51:09.509 111[16598:1880750] i的值是:7

2015-07-28 17:51:09.509 111[16598:1880752] j的值是:8

2015-07-28 17:51:09.509 111[16598:1880750] i的值是:8

2015-07-28 17:51:09.510 111[16598:1880752] j的值是:9

2015-07-28 17:51:09.510 111[16598:1880750] i的值是:9

我们看到打印顺序是交替进行的。 那么如何进行顺序操作呢。只需一行代码。

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    // 创建一个队列

    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    // 设置最大线程数

    queue.maxConcurrentOperationCount = 5;

    // 创建一个A操作

    NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{

        for (int i = 0; i<10; i++) {

            NSLog(@"i的值是:%d",i); 

        }

    }];

    // 创建一个B操作

    NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{

        for (int j = 0; j<20; j++) {

            NSLog(@"j的值是:%d",j);

        }

    }];

 // 添加依赖 B要在A打印完在进行打印 所以是B依赖于A 那么只需要添加如下代码即可完成

  [operationB addDependency:operationA];

    // 分别加入到队列中

     [queue addOperation:operationA];

    [queue addOperation:operationB];

}

打印结果

2015-07-28 17:54:02.606 111[16625:1882738] i的值是:0

2015-07-28 17:54:02.609 111[16625:1882738] i的值是:1

2015-07-28 17:54:02.609 111[16625:1882738] i的值是:2

2015-07-28 17:54:02.609 111[16625:1882738] i的值是:3

2015-07-28 17:54:02.609 111[16625:1882738] i的值是:4

2015-07-28 17:54:02.609 111[16625:1882738] i的值是:5

2015-07-28 17:54:02.609 111[16625:1882738] i的值是:6

2015-07-28 17:54:02.609 111[16625:1882738] i的值是:7

2015-07-28 17:54:02.610 111[16625:1882738] i的值是:8

2015-07-28 17:54:02.610 111[16625:1882738] i的值是:9

2015-07-28 17:54:02.610 111[16625:1882738] j的值是:0

2015-07-28 17:54:02.610 111[16625:1882738] j的值是:1

2015-07-28 17:54:02.610 111[16625:1882738] j的值是:2

2015-07-28 17:54:02.610 111[16625:1882738] j的值是:3

2015-07-28 17:54:02.610 111[16625:1882738] j的值是:4

2015-07-28 17:54:02.611 111[16625:1882738] j的值是:5

2015-07-28 17:54:02.611 111[16625:1882738] j的值是:6

2015-07-28 17:54:02.611 111[16625:1882738] j的值是:7

2015-07-28 17:54:02.611 111[16625:1882738] j的值是:8

2015-07-28 17:54:02.611 111[16625:1882738] j的值是:9

顺序操作请求完成。

iOS 处理多个网络请求的并发的情况的更多相关文章

  1. iOS面试题--网络--如何处理多个网络请求的并发的情况

    如何处理多个网络请求的并发的情况 一.概念 1.并发 当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配 ...

  2. iOS 多网络请求同步并发

    iOS中经常会用到多线程,在多线程中有一个线程组的概念(group),创建多个线程组任务,多组任务都完成之后,就会进入dispatch_group_notify队列中. 同时多线程中还有一个信号量的概 ...

  3. iOS 多个异步网络请求全部返回后再执行具体逻辑的方法

    对于dispatch多个异步操作后的同步方法,以前只看过dispatch_group_async,看看这个方法的说明: * @discussion * Submits a block to a dis ...

  4. iOS开发——post异步网络请求封装

    IOS中有许多网络请求的函数,同步的,异步的,通过delegate异步回调的. 在做一个项目的时候,上网看了很多别人的例子,发现都没有一个简单的,方便的异步请求的封装例子.我这里要给出的封装代码,是异 ...

  5. iOS 自己封装的网络请求,json解析的类

    基本上所有的APP都会涉及网络这块,不管是用AFNetWorking还是自己写的http请求,整个网络框架的搭建很重要. 楼主封装的网络请求类,包括自己写的http请求和AFNetWorking的请求 ...

  6. iOS NSURLConnection和异步网络请求

    在日常应用中,我们往往使用AFNetworking等第三方库来实现网络请求部分.这篇文章会简要地介绍一下如何使用NSURLConnection来进行异步的网络请求. 我们先看一个小demo - (vo ...

  7. ios MVVM实践 刷新网络请求+tableView展示数据

    [实现效果] [目录结构相关] 此示例展示用的是MVVM结构形式,表述如下 M:数据Model的存储,可以用来对属性进行处理.(即胖model概念,上图中xx万人订阅这个处理方法写在Model内) V ...

  8. iOS项目中的网络请求和上下拉刷新封装

    代码地址如下:http://www.demodashi.com/demo/11621.html 一.运行效果图 现在的项目中不可避免的要使用到网络请求,而且几乎所有软件都有上下拉刷新功能,所以我在此对 ...

  9. 移动开发在路上-- IOS移动开发 五 网络请求封装

    接着上次的讲,这次我们讲 网络请求的封装  打开创建的项目,让我们一起来继续完成他, 上次我们说到GET请求地址的拼接: 我们接着上次的继续完善: 下边我们要定义的是 block //定义block ...

随机推荐

  1. Qt操作xml文件(增删改功能)

    这个例子是在根据网上博客<Qt数据库(XML)>改写的一个操作XML的实现. 借鉴了很多里面的代码,大家可以结合上面的博客对照,相信你肯定会对XML的操作熟练起来. 我建立的是Qwidge ...

  2. 面向对象编程(八)——this关键字

    很多人一提起它,就说“当前对象”,可到底什么是当前对象,是什么当前对象,他自己也不清楚. this(隐式参数) 普通方法中,this总是指向当前调用该方法的对象. 构造方法中,this总是指向正要初始 ...

  3. Thread 线程

    线程 Join 一线程里面调用另一线程join方法时,表示将本线程阻塞直至另一线程终止时再执行 using System.Linq; using System.Text; using System.T ...

  4. 作业一直"执行"

    背景:一个作业有7个步骤,前面的步骤成功/失败都转到下一步,直至最后退出,作业计划是每天早上8点执行.步骤中的语句是例行检查脚本,之前的历史记录都是一分钟内完成.此次重启数据库服务器后,检查发现此作业 ...

  5. Using Amazon API Gateway with microservices deployed on Amazon ECS

    One convenient way to run microservices is to deploy them as Docker containers. Docker containers ar ...

  6. 音乐播放器 AVAudioPlayer、定时器、UISlider

    #import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> @interface ViewController ...

  7. display:flex 多栏多列布局

    转自:http://www.360doc.com/content/14/0811/01/2633_400926000.shtml display:flex 多栏多列布局浏览器支持情况:火狐直接支持w3 ...

  8. Swift实战-豆瓣电台(四)歌曲列表的展现

    观看地址 http://v.youku.com/v_show/id_XNzMwNDE0OTA4.html 这节的主要内容是如何利用cell展现获取到的数据. 首先申明两个数组来储存我们获取到的数据 v ...

  9. p++ ++p

    1.P++是先使用这个变量,使用完了再加1,你的例子就是,先输出,再加一++P是先加一,在使用变量 eg: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1 ...

  10. 转:MIME(Multipurpose Internet Mail Extensions)类型

    MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型.是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器 ...