美文网首页ios
iOS网络优化之设置合理请求并发数

iOS网络优化之设置合理请求并发数

作者: 小凉介 | 来源:发表于2018-06-30 22:43 被阅读141次

作者大神Q原创,谢绝转载,谢谢,demo地址 NetworkArchitecture

现在写文章越来越感觉有点累,因为很多时候本来只打算讲某个点,但是写着写着会涉及到的越多,所以不知不觉越写越多,甚至有的我也不了解,需要在写的同时去研究,不过好处是通过写文章来发现自己的不足及需要学习的地方。

就拿这篇文章来说,本来就只是打算写iOS网络优化之设置合理的请求并发数,但是写着写着想可能看到的同学还需要知道一些网络层架构的知识,就又写了简单的网络层架构的文章,哎,写着写着天都黑了。

网络请求简单介绍

关于HTTP

首先,HTTP是超文本传输协议,是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,其主要特点有如下:

  1. 支持客户/服务器模式;

  2. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快;

  3. 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记;

  4. 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间;

  5. 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTP1.1

既然上面提到了HTTP是基于请求与响应的,且最主要的两个特点就是无连接和无状态,但需要说明的是,虽然是无连接的,但其底层也就是传输层大多却是基于 TCP面向连接的通信方式,因此,这里的无连接指的是:当server端和client端进行通讯的时候,client端向server端发起请 求,server端接收请求之后返回给client端一个响应,之后就会断开不再继续保持连接了;这样有一个好处就是对于只有一次访问的连接来说不仅节省 资源还很高效,但很明显,如果client端还想继续多次访问server端就需要重新建立连接也就是会多次进行TCP的“三次握手,四次挥手”的过程, 这样一来并没有节省资源而且还很低效,因此,使用keep-alive(又称持久连接、连接重用)可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,避免了建立或者重新建立连接的次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的TCP连接意味着更少的系统内核调用,socket的accept()和close()调用)。

HTTP 1.0 中keep-alive默认是关闭的,需要在HTTP头加入"Connection: Keep-Alive",才能启用Keep-Alive;HTTP 1.1中默认启用Keep-Alive,如果加入"Connection: close ",才关闭。目前大部分浏览器都是用HTTP 1.1协议,也就是说默认都会发起Keep-Alive的连接请求了,所以是否能完成一个完整的Keep- Alive连接就看服务器设置情况。

设置合理的并发数

为何设置并发数?

Screen Shot 2018-06-30 at 7.09.52 PM.png

在这里我们所说到情况是没有HTTP Pipeline(管道化)的情况,如上图如果我们建立了一个TCP连接,假设这个时候客户端有3个并发请求,那么必须request 1发出并且得到服务端的response后request 2才能发出,同理request 3。这样并发数多的时候排在后面的就要一直等。有些业务场景会出现多个Request集中产生的情况,此时我们需要设置一个合理的并发数。并发数如果太小,会导致“劣质”的请求block住“优质”的请求。如果并发数太大,带宽有限的场景下,会增加请求的整体延迟。

如何设置并发数

有的人可能会想既然如此我们可以通过设置TCP连接数来控制并发数,那么怎么设置呢?其实很简单通过 httpMaximumC运营商onnectionsPerHost设置,目前比较知名的开源网络请求框架比如AFNetworking和Alamofire都没有设置默认连接数。据说2G网络下一次只能维持一个TCP,3G是2个,4G和wifi是不限,最好是6个。为什么是据说,因为第一我们考证过,第二我测试的结果好像不是这样,但很多大牛都是这么说的,哈哈,如果不对这个锅我可不背。

不过怎样,这种方式都是不合理的,为什么呢?

当设置如下代码:

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPMaximumConnectionsPerHost = 2
configuration.timeoutIntervalForRequest = 30
let manager = Alamofire.Manager(configuration: configuration)

如图所示,前8个请求是成功的,后面的都 timeout 了,其实看过上面那张图之后这很好理解了。那正确的设置请求并发数的姿势是怎么样的呢?一个解决方案是在自定义的异步 NSOperation 子类中包装您的请求,然后使用操作队列的 maxConcurrentOperationCount 控制并发请求数,而不是 HTTPMaximumConnectionsPerHost 参数。以下我们通过Alamofire举例,AFNetworking实际上是一样的。

gjXC8.png

并发数设置实战

首先我们对创建一个ConcurrentOperation基类,这部分苹果官方文档也有Concurrency Programming Guide

public class ConcurrentOperation : Operation {
    
    //Mark: - Types
    enum State {
        case Ready, Executing, Finished
        
        func keyPath() -> String {
            switch self {
            case .Ready:
                return "isReady"
            case .Executing:
                return "isExecuting"
            case .Finished:
                return "isFinished"
            }
        }
    }
    
    //Mark: - Properties
    var state = State.Ready {
        willSet {
            willChangeValue(forKey: newValue.keyPath())
            willChangeValue(forKey: state.keyPath())
        }
        didSet {
            didChangeValue(forKey: oldValue.keyPath())
            didChangeValue(forKey: state.keyPath())
        }
        
    }
    
    override init() {
        state = .Ready
        
        super.init()
    }
    
    //Mark: - Operation
    public override var isReady: Bool {
        return super.isReady && state == .Ready
    }
    
    public override var isExecuting: Bool {
        return state == .Executing
    }
    
    public override var isFinished: Bool {
        return state == .Finished
    }
    
    public override var isAsynchronous: Bool {
        return true
    }
    
    func completeOperation() {
        state = .Finished
    }
    

}

然后再讲请求包装在ConcurrentOperation子类中

class NetworkOperation : ConcurrentOperation {
    
    //定义属性,当你实例化
    //这个对象时,将提供,并将在请求最终启动时使用
    //
    //在这个例子中,我将跟踪(a)URL;和(b)当请求完成时关闭调用
    
    let URLString: String
    let networkOperationCompletionHandler: (_ responseObject: Any?, _ error: Error?) -> ()
    
     //我们还将跟踪所产生的请求操作,以防我们需要稍后取消它
    
    weak var request: Alamofire.Request?
    
     //定义捕获发出请求时使用的所有属性的init方法
    
    init(URLString: String, networkOperationCompletionHandler: @escaping (_ responseObject: Any?, _ error: Error?) -> ()) {
        self.URLString = URLString
        self.networkOperationCompletionHandler = networkOperationCompletionHandler
        super.init()
    }
    
    
    //当操作实际开始时,这是将被调用的方法
    override func main() {

        request = Alamofire.SessionManager.cmInstance.request(URLString)
            .responseJSON { response in

                //个人而言,我只是在init中传递给我的完成处理程序
                self.networkOperationCompletionHandler(response.result.value, response.result.error)

                // now that I'm done, complete this operation

                self.completeOperation()
        }
    }
    
    //支持取消请求,万一我们需要它
    override func cancel() {
        request?.cancel()
        super.cancel()
    }
}

使用就很简单了

    let queue = OperationQueue()
    queue.maxConcurrentOperationCount = 2
    
    for _ in 0 ..< 50{
        let operation = NetworkOperation(URLString: "你的url") { responseObject, error in

            if responseObject == nil {

                print("failed")
            } else {

                print("succed")
            }
        }
        queue.addOperation(operation)
    }

接下来你需要做的是通过监听网络环境通过maxConcurrentOperationCount设置合理的并发数,比如4G和Wifi下设置成6,当网络环境较差时可以适当降低并发数,3G设置成2。

参考文章:
关于HTTP中的keep-alive
NSURLSession concurrent requests with Alamofire

相关文章

  • iOS网络优化之设置合理请求并发数

    作者大神Q原创,谢绝转载,谢谢,demo地址 NetworkArchitecture。 现在写文章越来越感觉有点累...

  • 网络请求优化之取消请求

    网络请求优化之取消请求 网络请求优化之取消请求

  • 设置请求并发数

    一、请求超时 二、多任务无顺序 自动关联 手动关联 三、多任务有顺序

  • iOS性能调优

    1.iOS 性能调优2.iOS性能调优(全)---内存优化和UI优化3.深度优化iOS网络模块4.iOS网络请求优...

  • 网络优化

    6.网络优化 客户端网络优化 多个请求合并为一个请求 保持长连接,设置请求header的connection:ke...

  • iOS中AFNetworking的实现分析

    1.AFN进行数据请求会开辟多条线程吗? 1)这里在operation队列中设置了最大并发数是1,让所有网络请求和...

  • iOS发送网络请求时设置HTTP代理

    需求:iOS发送网络请求时设置HTTP代理 解决方法:利用NSURLSession发送网络请求,并进行相应的设置。...

  • IOS 网络并发请求

    现在有一个需求:某个页面中的数据是通过三个接口给出的,现在需要三个接口中的数据全部返回后再一起展示全部数据。需求分...

  • 网络请求

    ios开发 合理封装请求接口 概述 如今大多的app都会与网络打交道,作为开发者 合理的对网络后台请求接口进行封装...

  • 【iOS】iOS电量优化方案

    1、 网络方面的优化 请求前判断网络状态,网络不可用,不要尝试执行网络请求; 请求前设置合适的超时时间,避免长时间...

网友评论

  • 小蜜蜂Bee:大神666
    小蜜蜂Bee:@大神Q 辛苦啦
    小凉介:写的累成狗,从下午5点钟写到现在,写这篇文章的同时顺带写了网络层架构的文章https://www.jianshu.com/p/a554448121b4,希望能帮助到你

本文标题:iOS网络优化之设置合理请求并发数

本文链接:https://www.haomeiwen.com/subject/cbcxuftx.html