1、web后台对大批量的繁重的io任务需要解耦使用分布式异步技术,否则会使接口阻塞,并发延迟,一般就选celery好了。此篇的取代主要是针对取代celery的worker模式。没有涉及到周期和定时模式。

2、对我来说celery提供了  分布式,任务路由,超时杀死,任务过期丢弃,任务限速,并发模型选择,并发池大小这些功能。

3、此篇除了并发模型固定为了线程模式,其余的特点都实现了。基本上的代码复用了之前使用celery框架的代码,只有任务调度变了,所以从celery改为自定义只花了3小时就改过来了。

4、具体是先实现基本骨架,然后使用23种设计模式中的模板模式继承基类,实现其中一个方法。也就是原来被celery 的@app.task装饰的东西,现在改为了继承和重写基类方法。

5、如果需要使用celery的进程工作模式,可以在import之后加一行ThreadPoolExcutor = ProcessPoolExecutor,就能很容易换成进程模式了。

如果需要使用celery的gevent工作模式,可以import gevent ,然后monkey.patch_all()

  1. # -*- coding: utf-8 -*-
  2. # @Author : ydf
  3. """
  4. 用来取代celery框架的,
  5. 改为使用自定义架构
  6. """
  7. import typing
  8. import abc
  9. import threading
  10. from multiprocessing import Process
  11. import json
  12. import time
  13.  
  14. from app.utils_ydf import BoundedThreadPoolExecutor, RedisMixin, decorators, LoggerMixin, LogManager
  15. from app.apis.list_page_live_price.live_price_celery_app import live_price_deco, bulk_price_live_deco
  16. from app.constant import icon_list
  17.  
  18. from app.apis.cnbooking.cnbooking_core import CnbookingHotelPriceQuerier, CnbookingHotelPriceQuerierInternational
  19. from app.apis.daolv.hotel_detail import query_hoteldetail_price
  20. # from app.apis.elong.elong_detail_priceinfo2 import detail_priceinfo
  21. from app.apis.elongin.elong_in_detail import elong
  22. from app.apis.haoqiao.core import search2
  23. from app.apis.jltour.jl_price import get_jl_tour_price
  24. from app.apis.qunar.core import getPrice_in, getPrice
  25. from app.apis.yingli.core import get_detial
  26.  
  27. # from app.apis.expedia.expedia_hotel_price import get_expedia_price
  28. from app.apis.ctrip.ctriphotelm import ctripPriceIn, ctripPrice
  29.  
  30. # 导入批量获取比价的函数
  31. from app.apis.elong.elong_cn_bulk_request import elong_cn_bulk_request_price
  32. from app.apis.jltour.jl_bulk_price_querier import JltourBulkPriceQuerier
  33. from app.apis.daolv.daolv_bulk_price_querier import DaolvBulkPriceQuerier
  34.  
  35. QUENEN_NAME_ELONG = 'compare.quenen.elong'
  36. QUENEN_NAME_QUNAR = 'compare.quenen.qunar'
  37. QUENEN_NAME_DAOLV = 'compare.quenen.daolv'
  38. QUENEN_NAME_HAOQIAO = 'compare.quenen.haoqiao'
  39. QUENEN_NAME_CNBOOKING = 'compare.quenen.cnbooking'
  40. QUENEN_NAME_PROFIT = 'compare.quenen.profit'
  41. QUENEN_NAME_JLTOUR = 'compare.quenen.jltour'
  42. QUENEN_NAME_CTRIP = 'compare.quenen.ctrip'
  43. QUENEN_NAME_ELONG_CN = 'compare.quenen.elong_cn'
  44.  
  45. TASK_EXPIRE_TIME = 15 # 任务过期时间,消费时候比提交任务时候晚了15秒则不执行这个任务
  46. TASK_TIMEOUT = 20 # 任务(函数)运行超时,自动杀死的时间配置
  47.  
  48. logger_redis = LogManager('logger_redis').get_logger_and_add_handlers(5, is_add_stream_handler=False, log_filename='logger_redis.log')
  49.  
  50. class BaseExecuor(RedisMixin, LoggerMixin):
  51. """
  52. 单个酒店查询的基类
  53. """
  54.  
  55. def __init__(self, redis_list_key_name, thread_pool_nums, every_request_interval_time, platfrom_name):
  56. """
  57.  
  58. :param redis_list_key_name: 每个平台的redis任务键
  59. :param thread_pool_nums: 线程池最大数量
  60. :param every_request_interval_time: 每隔多少秒方任务到线程池,用于限制频率
  61. :param platfrom_name: 平台名字
  62. """
  63. self._redis_list_key_name = redis_list_key_name
  64. self._thread_pool_nums = thread_pool_nums
  65. self._every_request_interval_time = every_request_interval_time
  66. self._platfrom_name = platfrom_name
  67. self._pool = BoundedThreadPoolExecutor(self._thread_pool_nums)
  68. self._t0 = time.time()
  69. self._count_per_second = 0
  70. self._lock = threading.Lock()
  71. self.logger_with_file.debug(f'监听的队列是 {self._redis_list_key_name}')
  72.  
  73. def _shedul_a_task(self, redis_task: str):
  74. hotel_map_item, arrival_date, departure_date, adults, children_str, timestamp = redis_task.split('@@')
  75. hotel_map_item = json.loads(hotel_map_item)
  76. adults = int(adults)
  77. children_str = '' if children_str in (0, '') else children_str # 空的会出现4个@符号在一起,split出错
  78. if time.time() - float(timestamp) < TASK_EXPIRE_TIME:
  79. self.logger_with_file.debug(f'未过期,执行这个任务 {redis_task} ')
  80. time.sleep(self._every_request_interval_time)
  81. lowest_price_key = 'lowestprice_' + hotel_map_item['_id'] + '_' + arrival_date + '_' + departure_date + '_' + str(adults) + '_' + str(children_str)
  82. if not self.redis_db_hotel.exists(lowest_price_key): # TODO 如果此马踏飞燕id不存在最低价则请求
  83. self._pool.submit(self.execute_specific_task, hotel_map_item, arrival_date, departure_date, adults, children_str)
  84. else:
  85. self.logger_with_file.warning(f'此马踏飞燕酒店 {hotel_map_item["_id"]} 已经有最低价了,此次不请求 {self._platfrom_name} 这个平台')
  86. else:
  87. self.logger_with_file.warning(f'时间超过 {TASK_EXPIRE_TIME},放弃这个任务 {redis_task}')
  88.  
  89. def start(self):
  90. while True:
  91. try:
  92. time_redis_0 = time.time()
  93. redis_task_bytes = self.redis_db_hotel.rpop(self._redis_list_key_name) # 得到一个键hotel_map_item,arrival_date, departure_date, adults, children_str,timestamp
  94. if redis_task_bytes:
  95. redis_task = redis_task_bytes.decode('utf8')
  96. self.logger_with_file.debug(f'从 {self._redis_list_key_name} 键取出的内容是--> {redis_task} redis取出耗时 {time.time() - time_redis_0}')
  97. self._shedul_a_task(redis_task)
  98. else:
  99. if time.time() - self._t0 > 5: # 为了不频繁写这个日志主要是
  100. self._t0 = time.time()
  101. self.logger.debug(f'平台 {self._platfrom_name} {self._redis_list_key_name} 队列中没有任务, redis耗时 {time.time() - time_redis_0}')
  102. time.sleep(self._every_request_interval_time)
  103. except Exception as e:
  104. self.logger_with_file.exception(e)
  105. time.sleep(self._every_request_interval_time)
  106.  
  107. @abc.abstractmethod
  108. def execute_specific_task(self, hotel_map_item_or_list: typing.Union[dict, list], arrival_date__, departure_date__, adults__, children_str__):
  109. raise NotImplemented
  110.  
  111. class BaseBulkExcutor(BaseExecuor):
  112. """批量查询的基类"""
  113.  
  114. def execute_specific_task(self, hotel_map_item_or_list: typing.Union[dict, list], arrival_date__, departure_date__, adults__, children_str__):
  115. pass
  116.  
  117. def _shedul_a_task(self, redis_task: str):
  118. redis_task = json.loads(redis_task)
  119. hotel_map_item_list = redis_task['id_list']
  120. arrival_date, departure_date, adults, children_str, timestamp = redis_task['arrival_date'], redis_task['departure_date'], redis_task['adults'], redis_task['children_str'], redis_task['timestamp']
  121. adults = int(adults)
  122. children_str = '' if children_str in (0, '') else children_str # 空的会出现4个@符号在一起,split出错,用了0代替空字符串
  123. if time.time() - float(timestamp) < TASK_EXPIRE_TIME:
  124. self.logger_with_file.debug(f'未过期,执行这个任务 {redis_task} ')
  125. time.sleep(self._every_request_interval_time)
  126. self._pool.submit(self.execute_specific_task, hotel_map_item_list, arrival_date, departure_date, adults, children_str)
  127. else:
  128. self.logger_with_file.warning(f'时间超过 {TASK_EXPIRE_TIME},放弃这个任务 {redis_task}')
  129.  
  130. class QunarExecutor(BaseExecuor):
  131. def execute_specific_task(self, *args, **kwargs):
  132. @decorators.timeout(TASK_TIMEOUT)
  133. @live_price_deco('qunar', icon_list.ICON_QUNAR)
  134. def qunar_live(hotel_map_item, arrival_date, departure_date, adults, children_str):
  135. if not hotel_map_item['_id'].startswith('IN'):
  136. return getPrice(hotel_map_item['qunar_id'], arrival_date, departure_date)
  137. else:
  138. if children_str:
  139. qunar_children_age = children_str.replace(",", "|")
  140. qunar_children = len(children_str.split(","))
  141. else:
  142. qunar_children_age = ''
  143. qunar_children = 0
  144. return getPrice_in(hotel_map_item['qunar_id'], arrival_date, departure_date, adults, qunar_children, qunar_children_age)
  145.  
  146. qunar_live(*args, **kwargs)
  147.  
  148. class CnbookingExecutor(BaseExecuor):
  149. def execute_specific_task(self, *args, **kwargs):
  150. @decorators.timeout(TASK_TIMEOUT)
  151. @live_price_deco('cnbooking', icon_list.ICON_LONGTENG)
  152. def cnbooking_live(hotel_map_item, arrival_date, departure_date, adults, children_str):
  153. if not hotel_map_item['_id'].startswith('IN'):
  154. return CnbookingHotelPriceQuerier(hotel_map_item['cnbooking_id'], arrival_date, departure_date, adults, children_str).get_result()
  155. else:
  156. return CnbookingHotelPriceQuerierInternational(hotel_map_item['cnbooking_id'], arrival_date, departure_date, adults, children_str).get_result()
  157.  
  158. cnbooking_live(*args, **kwargs)
  159.  
  160. class ElongExecutor(BaseExecuor):
  161. def execute_specific_task(self, *args, **kwargs):
  162. @decorators.timeout(TASK_TIMEOUT)
  163. @live_price_deco('elong', icon_list.ICON_MASHANGZHU)
  164. def elong_live(hotel_map_item, arrival_date, departure_date, adults, children_str):
  165. if not hotel_map_item['_id'].startswith('IN'):
  166. pass
  167. # return detail_priceinfo(arrival_date, departure_date, hotel_map_item['elong_id'])
  168. else:
  169. return elong(arrival_date, departure_date, hotel_map_item['elong_id'], adults, children_str)
  170.  
  171. elong_live(*args, **kwargs)
  172.  
  173. class DaolvExecutor(BaseExecuor):
  174. def execute_specific_task(self, *args, **kwargs):
  175. @decorators.timeout(TASK_TIMEOUT)
  176. @live_price_deco('daolv', icon_list.ICON_DAOLV)
  177. def daolv_live(hotel_map_item, arrival_date, departure_date, adults, children_str):
  178. """不需要区分国内外"""
  179. return query_hoteldetail_price(hotel_map_item['daolv_id'], arrival_date, departure_date, adults, children_str)
  180.  
  181. daolv_live(*args, **kwargs)
  182.  
  183. class JltourExecutor(BaseExecuor):
  184. def execute_specific_task(self, *args, **kwargs):
  185. # noinspection PyUnusedLocal
  186. @decorators.timeout(TASK_TIMEOUT)
  187. @live_price_deco('jltour', icon_list.ICON_JLTOUR)
  188. def jltour_live(hotel_map_item, arrival_date, departure_date, adults, children_str):
  189. """不需要区分国内外"""
  190. return get_jl_tour_price(hotel_map_item['jltour_id'], arrival_date, departure_date, adults)
  191.  
  192. jltour_live(*args, **kwargs)
  193.  
  194. class HaoqiaoExecutor(BaseExecuor):
  195. def execute_specific_task(self, *args, **kwargs):
  196. @decorators.timeout(TASK_TIMEOUT)
  197. @live_price_deco('haoqiao', icon_list.ICON_HQ)
  198. def haoqiao_live(hotel_map_item, arrival_date, departure_date, adults, children_str):
  199. """不需要区分国内外"""
  200. haoqiao = hotel_map_item['haoqiao_id']
  201. hotel_id = haoqiao['hotel_id']
  202. city_id = haoqiao['city_id']
  203. return search2(hotel_id, city_id, arrival_date, departure_date, children_str, adults)
  204.  
  205. haoqiao_live(*args, **kwargs)
  206.  
  207. class YingliExecutor(BaseExecuor):
  208. def execute_specific_task(self, *args, **kwargs):
  209. # noinspection PyUnusedLocal,PyUnusedLocal
  210. @decorators.timeout(TASK_TIMEOUT)
  211. @live_price_deco('yingli', icon_list.ICON_JUYOUHUI)
  212. def yingli_live(hotel_map_item, arrival_date, departure_date, adults, children_str):
  213. """不需要区分国内外"""
  214. return get_detial(hotel_map_item['yingli_id'], arrival_date, departure_date)
  215.  
  216. yingli_live(*args, **kwargs)
  217.  
  218. class CtripExecutor(BaseExecuor):
  219. def execute_specific_task(self, *args, **kwargs):
  220. @decorators.timeout(TASK_TIMEOUT)
  221. @live_price_deco('ctrip', icon_list.ICON_CTRIP)
  222. def ctrip_live(hotel_map_item, arrival_date, departure_date, adults, children_str):
  223. if hotel_map_item['_id'].startswith('IN'):
  224. return ctripPriceIn(hotel_map_item['ctrip_id'], arrival_date, departure_date, adults, children_str)
  225. else:
  226. return ctripPrice(hotel_map_item['ctrip_id'], arrival_date, departure_date)
  227.  
  228. ctrip_live(*args, **kwargs)
  229.  
  230. # ###########################################################批量查询######################################################################################
  231. class JltourBulkExecutor(BaseBulkExcutor):
  232. def execute_specific_task(self, *args, **kwargs):
  233. @decorators.timeout(TASK_TIMEOUT)
  234. @bulk_price_live_deco(platform_name='jltour', platform_icon=icon_list.ICON_JLTOUR, platform_hotel_id_key='jltour_id')
  235. def jltour_bulk_request_price_live(hotel_map_item_list, arrival_date, departure_date, adults, children_str):
  236. hotel_id_list = [hotel_map_item['jltour_id'] for hotel_map_item in hotel_map_item_list]
  237. return JltourBulkPriceQuerier(hotel_id_list, arrival_date, departure_date, adults, children_str).get_result_list()
  238.  
  239. jltour_bulk_request_price_live(*args, **kwargs)
  240.  
  241. class ElongBulkExecutor(BaseBulkExcutor):
  242. def execute_specific_task(self, *args, **kwargs):
  243. @decorators.timeout(TASK_TIMEOUT)
  244. @bulk_price_live_deco(platform_name='elong', platform_icon=icon_list.ICON_MASHANGZHU, platform_hotel_id_key='elong_id')
  245. def elong_cn_bulk_request_price_live(hotel_map_item_list, arrival_date, departure_date, adults, children_str):
  246. hotel_id_list = [hotel_map_item['elong_id'] for hotel_map_item in hotel_map_item_list]
  247. price_result_list = elong_cn_bulk_request_price(hotel_id_list, arrival_date, departure_date, adults, children_str)
  248. return price_result_list
  249.  
  250. elong_cn_bulk_request_price_live(*args, **kwargs)
  251.  
  252. class DaolvBulkExecutor(JltourBulkExecutor):
  253. def execute_specific_task(self, *args, **kwargs):
  254. @decorators.timeout(TASK_TIMEOUT)
  255. @bulk_price_live_deco(platform_name='daolv', platform_icon=icon_list.ICON_DAOLV, platform_hotel_id_key='daolv_id')
  256. def daolv_bulk_request_price_live(hotel_map_item_list, arrival_date, departure_date, adults, children_str):
  257. hotel_id_list = [hotel_map_item['daolv_id'] for hotel_map_item in hotel_map_item_list]
  258. querier = DaolvBulkPriceQuerier(hotel_id_list, arrival_date, departure_date, adults, children_str)
  259. querier.set_is_real_time(is_real_time=False)
  260. return querier.get_result_list()
  261.  
  262. daolv_bulk_request_price_live(*args, **kwargs)
  263.  
  264. def start_executor(**kwargs):
  265. platfrom_name = kwargs['platfrom_name']
  266. if platfrom_name == '去哪':
  267. executor_class = QunarExecutor
  268. elif platfrom_name == '龙腾':
  269. executor_class = CnbookingExecutor
  270. elif platfrom_name == '艺龙国际':
  271. executor_class = ElongExecutor
  272. elif platfrom_name == '道旅':
  273. executor_class = DaolvBulkExecutor
  274. elif platfrom_name == '捷旅':
  275. executor_class = JltourBulkExecutor
  276. elif platfrom_name == '好巧':
  277. executor_class = HaoqiaoExecutor
  278. elif platfrom_name == '盈利':
  279. executor_class = YingliExecutor
  280. elif platfrom_name == '携程':
  281. executor_class = CtripExecutor
  282. CtripExecutor(**kwargs).start()
  283. elif platfrom_name == '艺龙国内':
  284. executor_class = ElongBulkExecutor
  285. else:
  286. raise ValueError('平台名字设置不正确')
  287. executor_class(**kwargs).start()
  288.  
  289. if __name__ == '__main__':
  290. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_QUNAR, 'thread_pool_nums': 300, 'every_request_interval_time': 0.02, 'platfrom_name': '去哪'}).start()
  291. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_CNBOOKING, 'thread_pool_nums': 300, 'every_request_interval_time': 0.02, 'platfrom_name': '龙腾'}).start()
  292. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_ELONG, 'thread_pool_nums': 300, 'every_request_interval_time': 0.15, 'platfrom_name': '艺龙国际'}).start()
  293. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_DAOLV, 'thread_pool_nums': 300, 'every_request_interval_time': 0.02, 'platfrom_name': '道旅'}).start()
  294. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_JLTOUR, 'thread_pool_nums': 300, 'every_request_interval_time': 0.1, 'platfrom_name': '捷旅'}).start()
  295. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_HAOQIAO, 'thread_pool_nums': 100, 'every_request_interval_time': 0.5, 'platfrom_name': '好巧'}).start()
  296. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_PROFIT, 'thread_pool_nums': 300, 'every_request_interval_time': 0.01, 'platfrom_name': '盈利'}).start()
  297. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_CTRIP, 'thread_pool_nums': 500, 'every_request_interval_time': 0.01, 'platfrom_name': '携程'}).start()
  298. Process(target=start_executor, kwargs={'redis_list_key_name': QUENEN_NAME_ELONG_CN, 'thread_pool_nums': 200, 'every_request_interval_time': 0.15, 'platfrom_name': '艺龙国内'}).start()

使用redis原生list结构作为消息队列取代celery框架。的更多相关文章

  1. 用redis实现支持优先级的消息队列

    http://www.cnblogs.com/tianqiq/p/4309791.html http://www.cnblogs.com/it-cen/p/4312098.html http://ww ...

  2. Redis学习之实现优先级消息队列

    很久没有写博客了,最近简单的学习了一下Redis,其中学习了一下用Redis实现优先级消息队列.关于更多更为详细的可以在www.redis.cn找到相关资料. 对于熟悉Redis的童鞋提到队列很自然的 ...

  3. 用 Redis 实现 PHP 的简单消息队列

    参考:PHP高级编程之消息队列 消息队列就是在消息的传输过程中,可以保存消息的容器. 常见用途: 存储转发:异步处理耗时的任务 分布式事务:多个消费者消费同一个消息队列 应对高并发:通过消息队列保存任 ...

  4. redis(五)---- 简单消息队列

    消息队列一个消息的链表,是一个异步处理的数据处理引擎.不仅能够提高系统的负荷,还能够改善因网络阻塞导致的数据缺失.一般用于邮件发送.手机短信发送,数据表单提交.图片生成.视频转换.日志储存等. red ...

  5. 消息队列介绍、RabbitMQ&Redis的重点介绍与简单应用

    消息队列介绍.RabbitMQ&Redis的重点介绍与简单应用 消息队列介绍.RabbitMQ.Redis 一.什么是消息队列 这个概念我们百度Google能查到一大堆文章,所以我就通俗的讲下 ...

  6. 进击的Python【第十一章】:消息队列介绍、RabbitMQ&Redis的重点介绍与简单应用

    消息队列介绍.RabbitMQ.Redis 一.什么是消息队列 这个概念我们百度Google能查到一大堆文章,所以我就通俗的讲下消息队列的基本思路. 还记得原来写过Queue的文章,不管是线程queu ...

  7. 基于Redis的消息队列php-resque

    转载:http://netstu.5iunix.net/archives/201305-835/ 最近的做一个短信群发的项目,需要用到消息队列.因此开始了我对消息队列选型的漫长路. 为什么选型会纠结呢 ...

  8. Redis中的Stream数据类型作为消息队列的尝试

    Redis的List数据类型作为消息队列,已经比较合适了,但存在一些不足,比如只能独立消费,订阅发布又无法支持数据的持久化,相对前两者,Redis Stream作为消息队列的使用更为有优势.   相信 ...

  9. [转载] 基于Redis实现分布式消息队列

    转载自http://www.linuxidc.com/Linux/2015-05/117661.htm 1.为什么需要消息队列?当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消 ...

随机推荐

  1. python网络编程(九)

    单进程服务器-非堵塞模式 服务器 #coding=utf-8 from socket import * import time # 用来存储所有的新链接的socket g_socketList = [ ...

  2. ES6 Set 和 Map

    ES5 模拟Set 与 Map 集合 Set 常用于检查对象中是否存在某个键名 Map集合常被用于获取已存的信息 所有对象的属性名必须是字符串,那么必须确保每个键名都是字符串类型且在对象中是唯一的 数 ...

  3. vue中 如何使用less

    首先肯定是vue-cli全部就位: 1,安装依赖: npm install less less-loader --save 2,修改build-webpack.base.config.js文件,配置l ...

  4. flask之信号和mateclass元类

    本篇导航: flask实例化参数 信号 metaclass元类解析 一.flask实例化参数 instance_path和instance_relative_config是配合来用的:这两个参数是用来 ...

  5. Redis的快照持久化-RDB与AOF

    Redis持久化功能 Redis为了内部数据的安全考虑,会把本身的数据以文件形式保存到硬盘中一份,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)的里边. 数据保存到硬盘的过程就称为“持久化 ...

  6. Unity2017灯光烘焙知识点

    去研究一下灯光探针,性能可以提升不少.

  7. ImportError: No module named _tkinter on macos

    MAC OS 10.11.6 lMacBook-Pro:~ xiaomilbq$ python Python 2.7.14 (default, Sep 22 2017, 00:05:22) [GCC ...

  8. [C#] .NET Core/Standard 1.X 项目中如何使用XmlIgnoreAttribute等标准范围外的内容,兼谈如何解决“violation of security transparency rules failed”(违反安全透明规则失败)异常

    作者: zyl910 一.缘由 XML序列化是一个很常用的功能,但对于.NET Core/Standard,其直到2.0版才内置支持XML序列化.具体来说, .NET Core 2.0 或 .NET ...

  9. 华为ap3010DN-V2刷出胖AP并配置接入POE交换机实现上网

    配置FAT AP二层组网示例 组网图形 图1 配置二层网络WLAN基本业务示例组网图 组网需求 如图1所示,FAT AP通过有线方式接入Internet,通过无线方式连接终端.现某企业分支机构为了保证 ...

  10. iostat各字段的来源和真实含义

    The primary tool for inspecting Linux disk performance is iostat. The output includes many important ...