跨平台高效HTTP队列实现方案之线程池基础组件.

移动端的http请求已经成为app必不可少的数据获取方式,但大多数网络请求模块主要焦点放在功能上,较少考虑到时间、空间等性能指标,时间主要是指请求时间,包括tcp建链的时间,数据传输时间,数据返回后处理或存储时间,空间主要指内存空间,主要是内存碎片及内存可用空间越来越小等问题。针对以上问题其实都是有解决办法的。

首先针对时间性能指标,应该使用多线程多连接并发复用技术,涉及到线程池技术、tcp连接复用技术,在线程池中对任务队列中的任务进行并发处理,同时tcp连接要采用复用技术,这样将大大减少请求时延,对大多数据http请求而言,tcp建连的时延远比数据传输时延要高,tcp连接复用技术可以大大减少http请求时间,达到提升时间性能指标的目的。同时采用多线程技术,支持并发,这样又可以增加客户端任务的并发,提升逻辑及界面的响应体验,同时减少服务器并发压力。反过来讲,如果不使用连接复用技术,对于服务器而言,压力在于建连,并发能力不变情况下,能够同时提供服务的用户数量必然受影响,因为进行n个请求,需要服务器分配n个sock资源,而采用复用连接技术,在并发能力不变的情况下,能够提供给更多的用户服务。对于复用的tcp连接,要有管理策略,即空闲策略,超过一定时长,自动释放该连接。现有的一些较知名软件,如微信、飞信在资源下载上都使用的是此技术。对于ios平台,ASI提供了此技术支持,AFNetwork则无此技术特征;android暂未对开放的http组件进行研究。

其次针对空间性能指标,此指标主要是在内存使用开销上,内存空间是有限的,当程序运行请求分配内存时,unix&linux系统基本上都是以4k为页基数,并且采用链表技术,当请求值小于4k时,从某页中获取并近回给申请者,以后续地址做为始址存入链表以便下次申请时使用,这样无疑有3点缺点: 1、申请时增加系统内存管理开销;2、释放内存时增加系统内存管理开销;3、碎片较多,当需要较大内存时,可能就会出现内存不足现象;因此合理使用内存池技术是有利于程序的内存管理及性能,不过要注意合理使用哦!

因此在http请求时使用内存池将不仅能够减少内存碎片问题,同时能够加速程序运行,因为从已分配的内存地址上获得空间比从系统申请空间要快,并且一个请求执行完后,内存块可以回收,也可以进行复用,具体策略也可以自己定,参考一些优秀的内存池,策略是有一个最大内存值,超过该值的空闲内存块,则释放,否则复用。对于每次请求的内存块大小,以4k的倍数为宜,这样可以最大程度减少内存碎片。


基于以上的一些技术方案,综合起来,概括如下:需要独立线程池,对某个队列的任务进行处理;需要独立tcp连接复用管理模块,对tcp连接进行管理;需要内存池,在具体任务执行时使用内存池分配内存;互相独立是最好的,这样在实现任务具体的业务逻辑时,可以自行组合,比如:可以使用内存池,也可以决定不用,这样并不需要修改太多代码,仅仅是在初始化时设置内存使用策略即可。

先看看线程池的结构设计吧:


                                                        





上图为线程池基础结构图,上层http组件对其进行二次开发,并在任务的创建时引入内存池即可实现上述的技术方案,这样做的目的是保持底层架构稳定,上层任务可以随意开发,其中TaskPolicy即上层使用时需实现并传入的策略,包括具体执行任务执行的回调方法,这样线程池才能通用,而不具有局限性。另外内存池也不在此结构内包含,整个线程池的内存在初始化时,基本已经固定下来,内存申请较少,而真正的内存申请在任务的创建及运行时发生,因此属于线程池上层范畴。

有了线程池基础组件,我们下一章再讲讲在此基础组件之上,如何建立任务及使用内存池技术。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线程池队列可以一起实现任务排队。当一个任务到来时,首先将其放入队列中排队。线程池中的空闲线程会从队列中取出任务并执行,当队列为空时,线程将等待新的任务到来。 以下是一个简单的示例代码: ```python import queue import threading class ThreadPool: def __init__(self, maxsize): self.maxsize = maxsize self.tasks = queue.Queue() self.workers = [] def submit(self, func, *args, **kwargs): self.tasks.put((func, args, kwargs)) self._create_worker() def _create_worker(self): if len(self.workers) < self.maxsize: worker = threading.Thread(target=self._process_tasks) self.workers.append(worker) worker.start() def _process_tasks(self): while True: try: func, args, kwargs = self.tasks.get() except queue.Empty: break else: func(*args, **kwargs) def my_task(i): print(f"Task {i} is running") if __name__ == "__main__": pool = ThreadPool(5) for i in range(10): pool.submit(my_task, i) ``` 在这个示例中,我们定义了一个 `ThreadPool` 类,它包含一个任务队列 `tasks` 和一个线程池 `workers`。通过 `submit` 方法,我们可以将一个任务添加到队列中。当队列中有任务时,线程池中的空闲线程会从队列中取出任务,并调用相应的函数进行处理。 在 `main` 函数中,我们创建了一个 `ThreadPool` 实例,并将 10 个任务提交到线程池中。由于线程池中最多可以同时运行 5 个线程,因此前 5 个任务会立即开始执行,后面的任务则会等待前面的任务完成后再执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值