同步、异步无障碍:Python异步装饰器指南
一、引言
Python异步开发已经非常流行了,一些主流的组件像MySQL、Redis、RabbitMQ等都提供了异步的客户端,再处理耗时的时候不会堵塞住主线程,不但可以提高并发能力,也能减少多线程带来的cpu上下文切换以及内存资源消耗。但在业务开发的时候一些第三方库没有异步的处理方式,例如OSS、CV、其他第三方提供的SDK以及自己封装的函数有耗时等,此时还是需要借助线程来加速,再异步中就不会堵塞主线程,因此封装一个异步装饰器可以更好的处理异步,让代码更简洁。
二、功能分析
-
支持同步函数使用线程加速
-
异、同步函数需支持 await 语法等待返回结果
-
异、同步函数需支持后台任务,无需等待
同步函数使用线程加速
同步函数使用线程,这还是挺简单的使用,内置库的 threading.Thread 就可以实现
import time
import threadingdef task1(name):print(f"Hello {name}")time.sleep(1)print(f"Completed {name}")t1 = threading.Thread(target=task1, args=("hui",))
t2 = threading.Thread(target=task1, args=("wang",))t1.start()
t2.start()t1.join()
t2.join()>>> out
Hello hui
Hello wang
Completed hui
Completed wang
- start()方法用于启动线程执行函数。
- join()方法用于等待线程执行结束。
但这样直接开线程的方式比较暴力,也不太好管理,因此可以想到线程池,进行线程复用与管理。Python内置的 concurrent.futures 模块提供了线程池和进程池的实现与封装。
import time
from concurrent.futures import ThreadPoolExecutordef task2(name):print(f"Hello {name}")time.sleep(1)return f"Completed {name}"with ThreadPoolExecutor(max_workers=2) as executor:future1 = executor.submit(task2, "hui")future2 = executor.submit(task2, "zack")print("ret1", future1.result())
print("ret2", future2.result())>>> out
Hello hui
Hello zack
ret1 Completed hui
ret2 Completed zack
异、同步函数需支持 await 语法
异、同步函数需支持 await 语法等待返回结果,异步函数本身就支持 await语法,这里主要是实现同步函数支持
await 语法,在python中可以await语法的对象有如下几大类:
- 协程对象(coroutine):定义了__await__方法的对象,异步框架中的协程函数都是此类型。
- 任务对象(Task):封装了协程的对象, 如 asyncio 中的 Task, trio中的Task。
- Future对象:表示异步操作结果的对象, 如 concurrent.futures.Future。
- 协程装饰器封装的对象:一些装饰器可以将普通函数或对象包装成可await的对象,如@asyncio.coroutine。
综上,凡是实现了__await__魔术方法的对象或者封装了协程/任务的对象,都可以被await,await会自动把对象交给事件循环运行,等待其完成。
常见的可await对象包括协程函数、任务对象、Future、被@coroutine装饰的函数等,这可以使异步代码更简洁。await对象可以暂停当前协程,等待异步操作完成后再继续执行。
import asyncioasync def coro_demo():print("await coroutine demo")async def task_demo():print("await task demo")async def coro():print("in coro task")# 创建 Task 对象task = asyncio.create_task(coro())await taskasync def future_demo():print("await future demo")future = asyncio.Future()await future# 这个装饰器已经过时
@asyncio.coroutine
def coro_decorated_demo():print("await decorated function demo")async def main():await coro_demo()await task_demo()await future_demo()await coro_decorated_demo()if __name__ == '__main__':asyncio.run(main())>>> out
DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" insteaddef coro_decorated_demo():await coroutine demo
await task demo
in coro task
await future demo
这个 @asyncio.coroutine 协程装饰器已经过时了,都是使用 async、await 语法替代。
下面是实现 __await__ 方法的demo
import asyncioclass AsyncDownloader:def __init__(self, url):self.url = urlself.download_ret = Nonedef __await__(self):print(f'Starting download of {self.url}')loop = asyncio.get_event_loop()future = loop.run_in_executor(None, self.download)yield from future.__await__()return selfdef download(self):print(f'Downloading {self.url}...')# 模拟下载过程import timetime.sleep(2)self.download_ret = f'{self.url} downloaded ok'async def main():print('Creating downloader...')downloader = AsyncDownloader('https://www.ithui.top/file.zip')print('Waiting for download...')downloader_obj = await downloaderprint(f'Download result: {downloader_obj.download_ret}')if __name__ == '__main__':asyncio.run(main())>>> out
Creating downloader...
Waiting for download...
Starting download of https://www.ithui.top/file.zip
Downloading https://www.ithui.top/file.zip...
Download result: https://www.ithui.top/file.zip downloaded ok
用 yield from 来迭代 future对象(符合__await__逻辑),并在结束时return self
异、同步函数需支持后台任务
异步、后台任务的好处与场景
-
减少主程序的等待时间
异步函数可以通过后台任务的方式执行一些耗时操作,如IO操作、网络请求等,而主程序无需等待这些操作完成,可以继续执行其他任务,从而减少程序总体的等待时间。
-
提高程序响应性能
后台任务的异步执行,可以避免主程序被长时间阻塞,从而改善程序的整体响应性能。用户无需长时间等待才能得到响应。
-
解决IO密集型任务阻塞问题
对于网络、文件IO等密集型任务,使用同步执行可能会导致长时间阻塞,而异步后台任务可以很好地解决这个问题,避免资源浪费。
-
良好的用户体验
后台任务的异步处理,给用户的感觉是多个任务同时在执行,实际上CPU在切换处理,这相比线性等待任务完成,可以提供更好的用户体验。
-
适用于不需要实时结果的任务
邮件发送、数据批处理、文件处理等不需要用户即时等待结果的任务非常适合通过异步方式在后台完成。
在python中同异步函数实现后台任务
-
异步函数可以通过 asyncio.create_task 方法实现后台任务
-
同步函数可以通过线程、线程池来实现
import asyncio
import time
from threading import Thread
from concurrent.futures import ThreadPoolExecutorasync def async_bg_task():print('async bg task running')await asyncio.sleep(3)print('async bg task completed')def sync_bg_task():print('sync bg task running')time.sleep(3)print('sync bg task completed')async def main():print('Starting main program')# 异步函数的后台任务asyncio.create_task(async_bg_task())# 同步函数的后台任务# with ThreadPoolExecutor() as executor:# executor.submit(sync_bg_task)# Thread(target=sync_bg_task).start()loop = asyncio.get_running_loop()loop.run_in_executor(executor=ThreadPoolExecutor(), func=sync_bg_task)print('Main program continues')await asyncio.sleep(5)if __name__ == '__main__':asyncio.run(main())>>> ThreadPoolExecutor out
Starting main program
sync bg task running
sync bg task completed
Main program continues
async bg task running
async bg task completed>>> Thread out
Starting main program
sync bg task running
Main program continues
async bg task running
sync bg task completed
async bg task completed>>> run_in_executor out
Starting main program
sync bg task running
Main program continues
async bg task running
async bg task completed
sync bg task completed
看输出结果可以发现在同步函数使用直接使用线程池 ThreadPoolExecutor 执行还是堵塞了主线程,然后 Thread 没有,通过 loop.run_in_executor 也不会阻塞。后面发现 是 with 语法导致的堵塞,with 的根本原因就是它会等待线程池内的所有线程任务完成并回收,所以主线程必须等同步函数结束后才能继续。一开始我还一以为是线程池使用了主线程的线程后面打印线程名称看了下不是,然后调试下就发现了with的问题。
import asyncio
import time
import threading
from concurrent.futures import ThreadPoolExecutorasync def async_bg_task():print(f"async_bg_task In thread: {threading.current_thread().name}")print('async bg task running')await asyncio.sleep(3)print('async bg task completed')def sync_bg_task(num):print(f"sync_bg_task{num} In thread: {threading.current_thread().name}")print(f'sync bg task{num} running')time.sleep(3)print(f'sync bg task{num} completed')async def main():print('Starting main program')# 异步函数的后台任务asyncio.create_task(async_bg_task())# 同步函数的后台任务thread_pool = ThreadPoolExecutor()# with thread_pool as pool:# for i in range(5):# pool.submit(sync_bg_task, i)for i in range(5):thread_pool.submit(sync_bg_task, i)threading.Thread(target=sync_bg_task, args=["thread"]).start()loop = asyncio.get_running_loop()loop.run_in_executor(ThreadPoolExecutor(), sync_bg_task, "loop.run_in_executor")print('Main program continues')print(f"Main program In thread: {threading.current_thread().name}")await asyncio.sleep(5)if __name__ == '__main__':asyncio.run(main())
三、具体封装实现
import asyncio
from concurrent.futures import ThreadPoolExecutor, Executordef run_on_executor(executor: Executor = None, background: bool = False):"""异步装饰器- 支持同步函数使用 executor 加速- 异步函数和同步函数都可以使用 `await` 语法等待返回结果- 异步函数和同步函数都支持后台任务,无需等待Args:executor: 函数执行器, 装饰同步函数的时候使用background: 是否后台执行,默认FalseReturns:"""def _run_on_executor(func):@functools.wraps(func)async def async_wrapper(*args, **kwargs):if background:return asyncio.create_task(func(*args, **kwargs))else:return await func(*args, **kwargs)@functools.wraps(func)def sync_wrapper(*args, **kwargs):loop = asyncio.get_event_loop()task_func = functools.partial(func, *args, **kwargs) # 支持关键字参数return loop.run_in_executor(executor, task_func)# 异步函数判断wrapper_func = async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapperreturn wrapper_funcreturn _run_on_executor
封装成了带参数的装饰器
-
executor: 函数执行器, 装饰同步函数的时候使用
- 可以传递指定的线程池,默认None 根据系统cpu核心数动态创建线程的数量
-
background: 用于标识是否后台执行,默认False
- 有点诟病同步函数的后台任务没有用到这个参数而是使用 await 语法控制,但在使用装饰器时候可以起到后台任务标识作用,别人一看有这个参数就知道是后台任务就不用细看函数业务逻辑
- 后续再看看怎么优化,大家有没有比较好建议
-
loop.run_in_executor(executor, task_func) 方法不支持关键字参数的传递,故而采用 task_func = functools.partial(func, *args, **kwargs) ,来构造一个不带参数的函数就可以方便使用了
测试demo
import asyncio
import time
from concurrent.futures import ThreadPoolExecutorfrom py_tools.decorators.base import run_on_executor
from loguru import loggerthread_executor = ThreadPoolExecutor(max_workers=3)@run_on_executor(background=True)
async def async_func_bg_task():logger.debug("async_func_bg_task start")await asyncio.sleep(1)logger.debug("async_func_bg_task running")await asyncio.sleep(1)logger.debug("async_func_bg_task end")return "async_func_bg_task ret end"@run_on_executor()
async def async_func():logger.debug("async_func start")await asyncio.sleep(1)logger.debug("async_func running")await asyncio.sleep(1)return "async_func ret end"@run_on_executor(background=True, executor=thread_executor)
def sync_func_bg_task():logger.debug("sync_func_bg_task start")time.sleep(1)logger.debug("sync_func_bg_task running")time.sleep(1)logger.debug("sync_func_bg_task end")return "sync_func_bg_task end"@run_on_executor()
def sync_func():logger.debug("sync_func start")time.sleep(1)logger.debug("sync_func running")time.sleep(1)return "sync_func ret end"async def main():ret = await async_func()logger.debug(ret)async_bg_task = await async_func_bg_task()logger.debug(f"async bg task {async_bg_task}")logger.debug("async_func_bg_task 等待后台执行中")loop = asyncio.get_event_loop()for i in range(3):loop.create_task(async_func())ret = await sync_func()logger.debug(ret)sync_bg_task = sync_func_bg_task()logger.debug(f"sync bg task {sync_bg_task}")logger.debug("sync_func_bg_task 等待后台执行")await asyncio.sleep(10)if __name__ == '__main__':asyncio.run(main())
测试详细输出
async_func start
async_func running
async_func ret endasync bg task <Task pending name='Task-2' coro=<async_func_bg_task() running at ...
sync_func start
async_func_bg_task start
async_func start
async_func start
async_func startsync_func running
async_func_bg_task running
async_func running
async_func running
async_func runningasync_func_bg_task end
sync_func ret endsync_func_bg_task start
sync bg task <Future pending cb=[_chain_future.<locals>._call_check_cancel() at ...
sync_func_bg_task 等待后台执行
sync_func_bg_task running
sync_func_bg_task end
四、源代码
HuiDBK/py-tools: 打造 Python 开发常用的工具,让Coding变得更简单 (github.com)
题外话
“不是只有程序员才要学编程?!”
认真查了一下招聘网站,发现它其实早已变成一项全民的基本技能了。
连国企都纷纷要求大家学Python!
世界飞速发展,互联网、大数据冲击着一切,各行各业对数据分析能力的要求越来越高,这便是工资差距的原因,学习编程顺应了时代的潮流。
在这个大数据时代,从来没有哪一种语言可以像Python一样,在自动化办公、爬虫、数据分析等领域都有众多应用。
更没有哪一种语言,语法如此简洁易读,消除了普通人对于“编程”这一行为的恐惧,从小学生到老奶奶都可以学会。
《2020年职场学习趋势报告》显示,在2020年最受欢迎的技能排行榜,Python排在第一。
它的角色类似于现在Office,成了进入职场的第一项必备技能。
如果你也想增强自己的竞争力,分一笔时代的红利,我的建议是,少加点班,把时间腾出来,去学一学Python。
因为,被誉为“未来十年的职场红利”的Python,赚钱、省钱、找工作、升职加薪简直无所不能!
目前,Python人才需求增速高达**174%,人才缺口高达50万,**部分领域如人工智能、大数据开发, 年薪30万都招不到人!
感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。
👉CSDN大礼包🎁:全网最全《Python学习资料》免费赠送🆓!(安全链接,放心点击)
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
工具都帮大家整理好了,安装就可直接上手!
三、最新Python学习笔记
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、Python视频合集
观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
五、实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、面试宝典
简历模板
如有侵权,请联系删除。
相关文章:
同步、异步无障碍:Python异步装饰器指南
一、引言 Python异步开发已经非常流行了,一些主流的组件像MySQL、Redis、RabbitMQ等都提供了异步的客户端,再处理耗时的时候不会堵塞住主线程,不但可以提高并发能力,也能减少多线程带来的cpu上下文切换以及内存资源消耗。但在业务…...
CodeSite for .NET Crack
CodeSite for .NET Crack CodeSite for.NET与Visual Studio集成,通过实时查看器日志记录系统提供对代码执行的更深入了解,该系统有助于在本地或远程执行代码时快速查找问题。超越传统的断点调试,在应用程序继续运行时记录应用程序的执行&…...
基于IMX6ULLmini的linux裸机开发系列九:时钟控制模块
时钟控制模块 核心 4个层次配置芯片时钟 晶振时钟 PLL与PFD时钟 PLL选择时钟 根时钟/外设时钟 系统时钟来源 RTC时钟源:32.768KHz 系统时钟:24MHz,作为芯片的主晶振使用 PLL和PFD倍频时钟 7路锁相环电路(每个锁相环电路…...
【数据结构与算法】1. 绪论
1. 绪论 1.1 数据结构 1.1.1 数据结构的基本概念 1.1.2 数据结构的三要素 数据结构三要素: 逻辑结构 划分方法一: 线性结构:线性表、栈、队列、串非线性结构:树、图 划分方法二: 集合结构线性结构树形结构网状&…...
2023年京东儿童智能手表行业数据分析(京东销售数据分析)
儿童消费市场向来火爆,儿童智能手表作为能够实现定位导航,信息通讯,SOS求救,远程监听,智能防丢等多功能的智能可穿戴设备,能够通过较为精准的定位功能和安全防护能力保障儿童的安全,因而广受消费…...
数据结构(6)
2-3查找树 2-结点:含有一个键(及其对应的值)和两条链,左链接指向2-3树中的键都小于该结点,右链接指向的2-3树中的键都大于该结点。 3-结点:含有两个键(及其对应的值)和三条链,左链接指向的2-3树中的键都小于该结点&a…...
C++学习|CUDA安装和配置
CUDA安装和配置 Windows下安装CUDAVS项目配置CUDA Windows下安装CUDA 第一步:先看自己NIVIDIA显卡适合什么版本的CUDA。打开电脑的“NIVIDIA控制面板”->系统信息->组件。会看到我的显卡驱动最高支持的CUDA版本是11.4.56。 第二步:去CUDA官网&…...
3.若依前后端分离版开发用户自定义配置表格功能
一、背景 在项目上线测试的时候,关于同一个界面的表格,不同的用户会出现不同的字段排列需求,有些用户希望把A字段排在最前面,有些用户则希望A字段不显示。针对这种情况,开发一个表格自定义配置的功能,每个…...
【操作系统】24王道考研笔记——第三章 内存管理
第三章 内存管理 一、内存管理概念 1.基本概念 2.覆盖与交换 覆盖技术: 交换技术: 总结: 3.连续分配管理方式 单一连续分配 固定分区分配 动态分区分配 动态分区分配算法: 总结: 4.基本分页存储管理 定义…...
Spring缓存深入解析:@Cacheable的使用详解
摘要:在本文中,我们将深入研究Spring框架中的Cacheable注解。我们会通过详细的Java示例,探讨如何使用这个功能强大的注解来提升应用程序性能。 一、什么是缓存? 在计算机科学中,缓存是一种存储技术,用于保…...
软件配置安装(破解)--- jdk下载配置
下载jdk 如果有oracle账号的话直接登录下载你想要的版本 不然可以尝试镜像站 HUAWEI镜像:https://repo.huaweicloud.com/java/jdk/ 安装 配置(细节) 这里的JAVA_HOME就是java的家,也就是解压(或安装)之后的java的目录ÿ…...
idea使用docker生成镜像(打包镜像,导入镜像,导出镜像)
1:先下载安装dockerdesktop,安装成功后 2: 在cmd执行docker -v,查看安装的docker版本 C:\Users\dell>docker -v Docker version 24.0.5, build ced09963:需要启动 dockerdesktop应用,才算启动docker&a…...
wazuh环境配置
目录 一、wazuh的安装 1.1官方仓库安装 1.2虚拟机OVA安装 1.2.1 然后执行下面命令 1.2.2 这里还要下载脚本和config.yml配置文件,用来生成证书编辑 1.2.3然后编辑config.yml文件,将下面的三个IP地址改为一样的 1.2.4运行./wazuh-certs-tool.sh以…...
【Linux】Linux下常用压缩解压缩指令及选项小结
0x00 前言 版本信息:Ubuntu 18.04.6 LTS 最后更新日期:2023.8.22 0x01 Linux下常用压缩解压缩指令小结 1.gzip指令 gzip file:压缩file文件为file.gz ,但是只能压缩文件不能压缩目录,且不保留源文件。若想打包目录…...
香蕉派社区推出带10G SFP+ 端口的Banana Pi BPI-R4 Wifi7开源路由器
香蕉派BPI-R4 根据著名Banana Pi品牌背后的公司Sinovoip提供的初步信息,他们即将推出的Banana Pi BPI-R4路由器板目前正在开发中。与之前的 Banana Pi R3 板相比,这在规格上将有显着提升。这就是我们目前所知道的。 您可以选择 R4 板的两种不同配置。具…...
A 题:震源属性识别模型构建与震级预测 :代码分析:
问题 1: 针对附件 1~8 中的地震波数据,找出一系列合适的指 标与判据,构建震源属性识别模型,进行天然地震事件(附件 1~7) 与非天然地震事件(附件 8)的准确区…...
源码分析CompletableFuture使用默认线程池ForkJoinPool的弊端
先说结论: 假如有20CompletableFuture任务并发执行时,都使用默认线程池ForkJoinPool,但cpu的核心数又小于3,那么就会新建20个线程(不使用默认线程池了),这20个线程相互竞争cpu资源和内存&#x…...
连接pgsql数据库 sslmode sslrootcert sslkey sslcert 参数的作用
sslmode 参数的作用 sslmode 参数用于指定数据库连接时使用的 SSL 加密模式。SSL(Secure Sockets Layer)是一种加密协议,用于保护数据在客户端和服务器之间的传输过程,以增加数据传输的安全性。sslmode 参数可以设置不同的值&…...
从零学算法3
3.给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “b”&…...
宠物小程序开发
在当今社会,宠物已成为许多人生活中不可或缺的一部分。宠物市场的持续增长为创业者提供了巨大的商机。然而,作为一个创业者,要在竞争激烈的宠物市场中脱颖而出并不容易。因此,开发一个专属于自己的宠物小程序成为了解决这一难题的…...
07-Vue基础之综合案例——小黑记事本
个人名片: 😊作者简介:一名大二在校生 🤡 个人主页:坠入暮云间x 🐼座右铭:懒惰受到的惩罚不仅仅是自己的失败,还有别人的成功。 🎅**学习目标: 坚持每一次的学习打卡 文章…...
vite4+vue3+electron23.3+ts桌面应用bs端开发 打包windows、linux、max三个系统的安装包
vite4vue3electron23.3ts桌面应用bs端开发 打包windows、linux、max三个系统的安装包 主要包依赖 "electron-store": "^8.1.0", //全局数据状态管理,可选择性安装"electron": "23.3.8","electron-builder": &q…...
限制 el-input 输入 emoji
1. 电脑如何输入 emoji 表情 ? 快捷键 win; 或 win. 2. 代码实现 <template><el-input v-model"input" placeholder"请输入内容" input"inputChange"></el-input> </template><script> export default {name: D…...
【AI】解决Number_Words的安装和使用
It appears that you encountered an error while trying to install the “Numbers_Words” package using the specific version 0.18.2 of the PEAR channel. The error message indicates that there was a problem unpacking the “Math_BigInteger-1.0.3” package, whi…...
开启MySQL的binlog日志
在/etc/my.cnf增加如下配置 #binlog相关 log-bin /testdata/mysql/log/bin/mysql-bin expire_logs_days 7 binlog-format ROW binlog_cache_size 4M max_binlog_cache_size 20G binlog_rows_query_log_events 1 binlog_row_image FULL sync_binlog 1 log_bin_trust_fun…...
【支付宝小程序】支付宝小程序自定义组件技术教程
🦖我是Sam9029,一个前端 Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-JS学习,CSS学习,Vue-2领域博主 **🐱🐉🐱🐉恭喜你,若此文你认为写的不错,不要吝啬你的赞扬,…...
CSDN编程题-每日一练(2023-08-23)
CSDN编程题-每日一练(2023-08-23) 一、题目名称:圆小艺二、题目名称:连续子数组的最大和三、题目名称:投篮一、题目名称:圆小艺 时间限制:1000ms内存限制:256M 题目描述: 最近小艺酱渐渐变成了一个圆滑的形状-球!! 小艺酱开始变得喜欢上球! 小艺酱得到n个同心圆。 …...
解决:Appium Inspector刷新页面一直加载转圈
目录 问题:Appium Inspector刷新页面一直加载转圈 解决办法: 1.进入设置页面-电池-后台耗电管理 2.找到下面3个应用,修改为允许后台高耗电 问题:Appium Inspector刷新页面一直加载转圈 1、手机进行操作后,Appium I…...
Apache Doris 入门教程34:Join 优化
Bucket Shuffle Join Bucket Shuffle Join 是在 Doris 0.14 版本中正式加入的新功能。旨在为某些 Join 查询提供本地性优化,来减少数据在节点间的传输耗时,来加速查询。 它的设计、实现和效果可以参阅 上面的图片展示了Bucket Shuffle Join的工作原理…...
【神州数码】BGP路由器案例
SwitchB、SwitchC和SwitchD位于AS200中,SwitchA位于AS100中。SwitchA和SwitchB共享一个相同的网络段11.0.0.0。而SwitchB和SwitchD彼此物理上不相邻。 则SwitchA的配置如下: SwitchA(config)#router bgp 100SwitchA(config-router-bgp)#neighbor 11.1.1…...
手机营销型网站建设/手游代理加盟哪个平台最强大
我正在为数据库实现一个漂亮的基本搜索引擎,用户可能会在其中包含不同类型的信息。搜索本身由几个联合组成,选择结果总是合并到3列中。然而,返回的数据正在从不同的表中获取。每个查询使用$ term进行匹配,我将其绑定到“ÿ…...
免费建站平台哪个靠谱/web网页制作成品免费
转贴:http://bbs.langtech.org.cn/frame.php?frameonyes&refererhttp%3A//bbs.langtech.org.cn/forumdisplay.php%3Ffid%3D20感谢原创作者.ICDM2006-介绍:数据挖掘领域最有影响力的18个算法ICDM是数据挖掘领域的顶级会议之一,在数据挖掘理论与应用领…...
网站建设 东八区/企业网站建设的重要性
部分代码(完整包见资源下载链接) 注:资源上传时默认付费,可以私信我,我看到会回复的 <!doctype html> <html><head><meta charset"utf-8"><meta http-equiv"X-UA-Compatib…...
如何用服务器代替空间做网站/百度手机app
该文章转载自 http://fann.im/blog/2012/04/12/difference-between-objectforkey-and-valueforkey-in-nsdictionary/ 感谢原作者 从 NSDictionary 取值的时候有两个方法,objectForKey: 和 valueForKey:,这两个方法具体有什么不同呢? 先从 NS…...
建一个网站需要哪些费用/软文发布平台与板块
文/小伊评科技还是那个结论,我不认为现阶段的鸿蒙OS能够在手机这种载体上真正的挑战Android以及IOS,但是未来就不一定了。作为例子,早些年微软凭借WindowPhone以及对于诺基亚的扶持都没能从IOS和安卓手上抢下市场,反而最后落得一个…...