当前位置: 首页 > news >正文

东莞做营销型网站的wordpress头部高度

东莞做营销型网站的,wordpress头部高度,山西正规网站建设报价公司,望牛墩镇做网站✨个人主页#xff1a; 北 海 #x1f389;所属专栏#xff1a; Linux学习之旅 #x1f383;操作环境#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 #x1f307;前言#x1f3d9;️正文1、什么是线程#xff1f;1.1、基本概念1.2、线程理解1.3、进程与线程的关系… ✨个人主页 北 海 所属专栏 Linux学习之旅 操作环境 CentOS 7.6 阿里云远程服务器 文章目录 前言️正文1、什么是线程1.1、基本概念1.2、线程理解1.3、进程与线程的关系1.4、简单使用线程 2、重谈地址空间2.1、页表的大小2.2、内存与磁盘的交互2.3、深入页表2.4、小结 3、线程小结3.1、再谈线程3.2、线程的优点3.3、线程的缺点3.4、线程的用途 总结 前言 将一份代码成功编译后可以得到一个可执行程序程序运行后相关代码和数据被 load 到内存中并且操作系统会生成对应数据结构比如 PCB对其进行管理及分配资源准备工作做完之后我们就可以得到一个运行中的程序简称为 进程对于操作系统来说光有 进程 的概念是无法满足高效运行的需求的因此需要一种执行粒度更细、调度成本更低的执行流而这就是 线程 Windows 中的线程 ️正文 1、什么是线程 1.1、基本概念 可能很多人第一次听说 线程 这个词是在 处理器 中比如今年 英特尔第 13 代酷睿 系列芯片就在其宣传页中提到了 线程 这个词 硬件上的 线程 概念我们这里不讨论接下来看看操作系统层面的 线程概念 教材观点 线程就是一个执行分支、执行粒度比进程更细、调度成本更低线程就是进程内部的一个执行流 内核观点 进程是承担系统资源分配的基本实体而线程是 CPU 运行的基本单位 线程是对以往进程概念的补充完善正确理解线程概念是一件十分重要的事 1.2、线程理解 注意以下理解是站在 Linux 系统的角度不同的系统具体实现方式略有差异 理解 线程 之前需要先简单回顾一下 进程 程序运行后相关的代码和数据会被 load 到内存中然后操作系统为其创建对应的 PCB 数据结构、生成虚拟地址空间、分配对应的资源并通过页表建立映射关系 详见 《Linux进程学习【进程地址】》 进程之间是相互独立 即使是 父子进程他们也有各自的 虚拟地址空间、映射关系、代码和数据可能共享部分数据出现修改行为时引发 写时拷贝机制 如果我们想要创建 其他进程 执行任务那么 虚拟地址空间、映射关系、代码和数据 这几样东西是必不可少的想象一下如果只有进程的概念并且同时存在几百个进程那么操作系统调度就会变得十分臃肿 操作系统在调度进程时需要频繁保存上下文数据、创建的虚拟地址空间及建立映射关系 为了避免这种繁琐的操作引入了 线程 的概念所谓 线程 就是额外创建一个 task_struct 结构并且该 task_struct 同样指向当前的虚拟地址空间并且不需要建立映射关系及加载代码和数据如此一来操作系统只需要 创建一个 task_struct 结构即可完成调度成本非常低 为什么切换进程比切换线程开销大得多 在 CPU 内部包括运算器、控制器、寄存器、MMU、硬件级缓存cache其中 硬件级缓存 cache 又称为 高速缓存遵循计算机设计的基本原则局部性原理会预先加载 部分用户可能访问的数据 以提高效率如果切换进程会导致 高速缓存 中的数据无法使用进程具有独立性重新开始 预加载这是非常浪费时间的对于 CPU 来说但切换线程就不一样了因此线程从属于进程切换线程时所需要的数据的不会发生改变这就意味值 高数缓存 中的数据可以继续使用并且可以接着 预加载 下一波数据 不同 CPU 的 高速缓存 大小不同足够大的高速缓存 先进的工艺 就可以得到一块性能优越的 CPU 注高速缓存中预加载的是公共数据并非线程的私有数据 进程process的 task_struct 称为 PCB线程thread的 task_struct 则称为 TCB 从今天开始无论是 进程 还是 线程都可以称为 执行流线程 从属于 进程当进程中只有一个线程时我们可以粗粒度的称当前进程为一个单独的执行流当进程中有多个线程时则称当前进程为多执行流其中每一个执行流都是一个个的线程 执行流的调度由操作系统负责CPU 只负责根据 task_struct 结构进行运算 若下一个待调度的执行流为一个单独的进程操作系统仍需创建 PCB 及 虚拟地址空间、建立映射关系、加载代码和数据但如果下一个待调度的执行流为一个线程操作系统只需要创建一个 TCB并将其指向已有的虚拟地址空间即可 现在面临着一个很关键的问题进程和线程究竟是什么关系 1.3、进程与线程的关系 进程是承担系统资源分配的实体比如 程序运行必备的虚拟地址空间、页表映射关系、相关数据和代码 这些都是存储在 进程 中的也就是我们历史学习中 进程 的基本概念 线程是 CPU 运行的基本单位程序运行时CPU 只认 task_struct 结构并不关心你是 线程 还是 进程不过线程 包含于 进程 中一个 进程 可以只有一个 线程也可以有很多 线程当只有一个 线程 时通常将其称为 进程但对于 CPU 来说这个 进程 本质上仍然是 线程因为 CPU 只认 task_struct 结构并且 PCB 与 TCB 都属于 task_strcut所以才说 线程是 CPU 运行的基本单位 总结进程是由操作系统将程序运行所需地址空间、映射关系、代码和数据打包后的资源包而 线程/轻量级线程/执行流 则是利用资源完成任务的基本单位 线程包含于进程中进程本身也是一个线程 我们之前学习的进程概念是不完整的引入线程之后可以对进程有一个更加全面的认识 通常将程序启动比如 main 函数中的这个线程称为 主线程其他线程则称为 次线程 实际上 进程 PCB TCB 虚拟地址空间 映射关系 代码和数据这才是一个完整的概念 以后谈及进程时就要想到 一批执行流可支配的资源 进程与线程的概念并不冲突而是相互成就 在 Linux 中认为 PCB 与 TCB 的共同点太多了于是直接复用了 PCB 的设计思想和调度策略在进行 线程管理 时完全可以复用 进程管理 的解决方案代码和结构这可以大大减少系统调度时的开销做到 小而美因此 Linux 中实际是没有真正的 线程 概念的有的只是复用 PCB 设计思想的 TCB 在这种设计思想下线程 注定不会过于庞大因此 Linux 中的 线程 又可以称为 轻量级进程LWP轻量级进程 足够简单且 易于维护、效率更高、安全性更强可以使得 Linux 系统不间断的运行程序不会轻易 崩溃 与 一切皆文件一样这种设计思想注定 Linux 会成为一款 卓越 的操作系统 别的系统采用的是其他方案比如 Windows 使用的是真线程方案为 TCB 额外设计了一逻辑这就导致操作系统在同时面临 PCB 和 TCB 时需要进行识别后切换成不同的处理手段存在不同的逻辑容易增加系统运行不稳定的风险这就导致 Windows 无法做到长时间运行需要通过重启来重置风险 此时我的电脑中同时存在几百个进程和几千个真线程可想而知操作系统的负担有多大 1.4、简单使用线程 如何验证 Linux 中的线程解决方案 简单使用一下就好了 接下来简单使用一下 pthread 线程原生库中的线程相关函数只是简单使用不涉及其他操作 #include iostream #include unistd.h #include pthread.husing namespace std;void *threadHandler1(void *args) {while (true){cout 我是次线程1我正在运行... endl;sleep(1);} }void *threadHandler2(void *args) {while (true){cout 我是次线程2我正在运行... endl;sleep(1);} }void *threadHandler3(void *args) {while (true){cout 我是次线程3我正在运行... endl;sleep(1);} }int main() {pthread_t t1, t2, t3; // 创建三个线程pthread_create(t1, NULL, threadHandler1, NULL);pthread_create(t2, NULL, threadHandler2, NULL);pthread_create(t3, NULL, threadHandler3, NULL);// 主线程运行while (true){cout 我是主线程 endl;sleep(1);}return 0; }编译程序时需要带上 -lpthread 指明使用 线程原生库 结果主线程三个次线程同时在运行 至于为什么打印结果会有点不符合预期这就涉及到 加锁 相关问题了后面再解决 使用指令查看当前系统中正在运行的 线程 信息 ps -aL | head -1 ps -aL | grep myThread | grep -v grep可以看到此时有 四个线程 细节1四个线程的 PID 都是 13039细节2四个线程的 LWP 各不相同细节3第一个线程的 PID 和 LWP 是一样的 其中第一个线程就是 主线程也就是我们之前一直很熟悉的 进程因为它的 PID 和 LWP 是一样的所以只需要关心 PID 也行 操作系统如何判断调度时是切换为 线程 还是切换为 进程 将待切换的执行流 PID 与当前执行流的 PID 进行比对如果相同说明接下来要切换的是 线程否则切换的就是 进程操作系统只需要找到 LWP 与 PID 相同的线程即可轻松锁定 主线程 线程是进程的一部分给其中任何一个线程发送信号都会影响到其他线程进而影响到整个进程 2、重谈地址空间 注当前部分是拓展与线程没有很大的关系但是一个比较重要的知识点 2.1、页表的大小 页表 是用来将 虚拟地址 和 物理地址 之间建立映射关系的除此之外页表 中还存在 其他属性 字段 众所周知在 32 位系统中存在 2^32 个地址一个内存单元大小是 1byte意味着虚拟地址空间 的大小为 4GB 假设极端情况每个地址都在页表中建立了映射关系其中页表的每一列大小都是 4 字节那么页表的大小就是 2^32 * 4 * 3 * 1byte 48GB这就意味着悲观情况下页表已经干掉 48GB 的内存了但现在电脑普遍都只有 16GB 内存更何况是几十年前的电脑 所以说页表绝对不是采用这种单纯 地址-地址 的映射方案 2.2、内存与磁盘的交互 操作系统从 磁盘 中读取数据时一次读取大量数据 比 多次读取少量数据 要快的多因为 磁盘 是外设每一次读取都必然伴随着寻址等机械运动机械硬盘无论是对于 内存 还是 CPU 这都是非常慢的为了尽可能提高效率操作系统选择一次 IO 大量数据的方式读取数据 通常 IO 的数据以 块 为基本单位在文件系统中一个 块 的大小为 4KB一个块由8个扇区组成单个扇区大小为 512Byte即使我们一次只想获取一个字节操作系统最低也会 IO 一个 数据块4KB 4KB 这个大小很关键 文件系统/编译器文件存储时需要以 4KB 为单位进行存储操作系统/内存读取文件或进行内存管理时也是以 4KB 为单位的 也就是说内存实际上是被切成大小为 4KB 的小块的在内存中单块内存4KB被称为 页 Page组成单块内存的边界类似于下标被称为 页框页帧 为了将内存中的 页 Page 进行管理需要 先描述在组织构建 struct page 结构体用于描述 页 Page 的状态比如是否为脏数据、是否已经被占用了因为存在很多 页 Page所以需要将这些 struct page 结构进行管理使用的就是 数组(天然有下标) struct page mem[N]其中 N 表示当前内存中的 页 Page 数量 struct page {int status; // 基础字段状态// 注意这个结构不能设计的太复杂了因为稍微大一点内存就爆了所以里面的属性非常少 };struct page mem[N]; // 管理 page 结构体的数组假设我们的内存为 4GB那么等分为 4KB 的 页 Page可以得到约 100w 个 页 Page其中 struct page 结构体不会设计的很大大小是 字节 级别的也就是说 struct page mem[100w] 占用的总大小不过 4~5MB对于偌大的内存来说可以忽略不计 内存管理的本质 申请无非就是寻找 mem 数组中一块未被使用的足量空间将对应的 页 Page 属性设置为已被申请并返回起始地址足量空间页框的起始地址使用将磁盘中的指定的 4KB 大小数据块存储至内存中对应的 页 Page 中释放将 页 Page 属性设置为可用状态 关于 mem 数组的查找算法内存分配算法LRU、伙伴系统等 重新审视 4KB为什么内存与磁盘交互的基本单位是 块4KB 这里就要提一下 局部性原理 了 局部性原理的特征 现代计算机预加载的理论基础允许我们提前加载正在访问数据的 相邻或者附加的数据数据预加载 局部性原理 的核心在于 预加载如果没有 局部性原理那么我们可能今天都用不上电脑因为如果没有这个原则那么内存在于磁盘交互时只能做到用户需要什么就申请什么这会直接拉低 CPU 的速度而速度极快的 磁盘 又非常贵 而 局部性原理 有效避免了这个问题用户访问数据时操作系统不仅会加载用想要访问的数据同时还会加载当前数据的临近数据如此一来就可以做到用户访问下一份数据时不必再次 IO尽量减少 IO 的次数 合理性用户访问的数据大多都是具有一定连续性的比如用户访问 668 号数据那么他下一次想访问的数据大概是 669 及以后因此可以提前加载 配合上 4KB 的块大小可以使得每次 IO 足量的数据并且有可能会多出起到 预加载 的效果 所以现在就可以回答为什么是 4KB IO 的基本单位内核系统/文件系统 都对其提供了支持利于通过 局部性原理 预测数据的命中情况尽可能提高效率 总结IO 的基本单位是 4KB内存实际上被划分成了很多个 4KB 的小块并存在相应的数据结构对其进行管理 2.3、深入页表 显然页表 绝对不可能动辄几十个 GB实际在根据 虚拟地址 进行寻址时页表 也有自己的设计逻辑 虚拟地址32 位操作系统 大小也就是 32 比特位大概也就是 4Byte通常将一个 虚拟地址 分割为三份10、10、12 10虚拟地址中的前 10 个比特位用于寻址 页表210虚拟地址中间的 10 个比特位用于寻找 页框起始地址12虚拟地址中的后 12 个比特位用于定位 具体地址偏移量 所以实际上在通过 页表 进行寻址时需要用到 两个页表为了方便演示仅包含一组 kv 关系 注“页表2” 中的 20 表示内存中的下标即 页框地址 通常将 “页表1” 称为 页目录“页表2” 称为 页表项 页目录使用 10 个比特位定位 页表项页表项使用 10 个比特位定位 页框地址偏移量使用 12 个比特位在 页 Page 中进行任意地址的寻址 所以即使是每个 物理地址 都被寻址的的极端情况下页表 总大小不过为(2^10 2^10) * (2^10 2^20)大约也就需要 4Mb 大小即可映射至每一个 物理内存但实际上 物理内存 并不会被时刻占满大多数情况下都是使用一部分因此实际 页表 大小不过 几十字节 像这种 页框起始地址偏移量 的方式称为 基地址偏移量是一种运用十分广泛的思想比如所谓的 类型int、double、char…都是通过 类型的起始地址类型的大小 来标识该变量大小的也就是说我们只需要 获得变量的起始地址即可自由进行偏移操作如果偏移过度了就是越界这也就解释了为什么取地址只会取到 起始地址 总结得益于 划分偏移 的思想使得页表的大小可以变得很小 扩展动态内存管理 实际上我们在进行 动态内存管理malloc/new 申请堆空间时操作系统 并没有立即在物理内存中申请空间因为你申请了可能不会立马使用而是 先在 虚拟地址 中进行申请成本很低当我们实际使用该空间时操作系统 再去 填充相应的页表信息申请具体的物理内存 像这种操作系统赌博式的行为我们已经不是第一次见了比如之前的 写时拷贝就是在赌你不会修改这样做的好处就是可以 最大化提高效率对于内存来说这种使用时再申请的行为会引发 缺页中断 当用户 动态申请内存 时操作系统只会在 虚拟地址 中申请具体表现为 返回一块未被使用的空间起始地址用户实际使用这块空间时遵循 查页表、寻址物理内存 的原则实际进行 查页表 操作时发现 页表项 没有记录此地址的映射关系于是就会引发 缺页中断发出对应的 中断信号陷入内核态通过 中断控制器 识别 中断信号 后做出相应的动作比如这里的动作是填充页表信息、申请物理内存 把 物理内存 准备好后用户就可以进行正常使用了整个过程非常快对于用户来说几乎无感知 同理在进行 磁盘文件读取 时也存在 缺页中断 行为毕竟你打开文件了并不是立即进行读写操作的 诸如这种 硬件级的中断行为 我们已经在 信号产生 中学过了即从键盘按下的那一刻发出硬件中断信号中断控制器识别为 键盘 发出的信号后去 中断向量表 中查找执行方法也就是 键盘 的读取方法 所以操作系统根本不需要关系 硬件 是什么样子只需要关心对方是否发出了 信号请求并作出相应的 动作执行方法 即可很好的实现了 解耦 对于 内存 的具体情况诸如是否命中、是否被占用、对应的 RWX 权限 需要额外的空间对其进行描述而 页表 中的 其他属性 列就包含了这些信息 对 内存 进行操作时势必要进行 虚拟地址到物理地址 之间的转换而 MMU 机制 页表信息 可以判断 当前操作 是否合法如果不合法会报错 注UK 权限用于区分当前是用户级页表还是内核级页表 比如这段代码 char *ps Change World!; *ps N; // 此时程序会报错需要赋值为字符否则无法编译结合 页表、信号 等知识解释整个报错逻辑 Change World! 属于字符常量存储在字符常量区中其中的权限为 Rchar *ps 属于一个指针变量指向字符常量的起始地址当我们进行 *ps No 操作时首先会将字符常量的地址转换为物理地址在转换过程中MMU 机制发现该内存权限仅为 R但 *ps 操作需要 W 权限于是 MMU 引发异常 - 操作系统识别到异常将该异常转换为 信号 - 并把 信号 发给出现问题的 进程 - 信号暂时被保存 - 在 内核态转为用户态 的过程中进行 信号处理 - 最终结果是终止进程也就是报错 程序运行后就会报错 2.4、小结 所以目前 地址空间 的所有组成部分我们都已经打通了再次回顾这种设计时会发现 用户压根不知道、也不需要知道虚拟地址空间之后发生的事只需要正常使用就好了当引发异常操作时操作系统能在 查页表 阶段就进行拦截而不是等到真正影响到 物理内存 时才报错 所谓的 虚拟地址空间 就是在进行设计时添加的一层 软件层它解决了 多进程时的物理内存访问问题、也解决了物理内存的保护问题同时还为用户提供了一个简单的虚拟地址空间做到了 虚拟与物理 的 完美解耦 这种设计思想就是计算机界著名的 所有问题都可以通过添加一层 软件层 解决这种思想早在几十年前就已经得到了运用 这种分层结构不仅适用于 操作系统还适用于 网络比如大名鼎鼎的 OSI 七层网络模型 3、线程小结 3.1、再谈线程 Linux 中没有 真线程有的只是复刻 进程 代码和管理逻辑的 轻量级线程LWP 线程 有以下概念 在一个程序中的一个执行路线就叫做 线程Thread或者说 线程 是一个进程内部的控制程序每一个进程都至少包含一个 主线程线程 在进程内部执行本质上仍然是在进程地址空间内运行在 Linux 系统中CPU 看到的 线程 TCB 比传统的 进程 PCB 更加轻量化透过进程地址空间可以看到进程的大部分资源将资源合理分配给每个执行流就形成了 线程执行流 3.2、线程的优点 线程 最大的优点就是 轻巧、灵活更容易进行调度 创建一个线程的代价比创建一个进程的代价要小得多调度线程比调度进程要容易得多线程占用的系统资源远小于进程可以充分利用多处理器的并行数量进程也可以在等待慢速 IO 操作时程序可以执行其他任务比如看剧软件中的 “边下边看” 功能对于计算密集型应用可以将计算分解到多个线程中实现比如 压缩/解压 时涉及大量计算对于 IO密集型应用为了提高性能将 IO操作重叠线程可以同时等待资源进行 高效IO比如 文件/网络 的大量 IO 需要可以通过 多路转接 技术提高效率 线程 的合理使用可以提高效率但 线程 不是越多越好而是 合适 最好让每一个线程都能参与到计算中 3.3、线程的缺点 线程 也是有缺点的 1、性能损失当 线程 数量过多时频繁的 线程 调度所造成的消耗会导致 计算密集型应用 无法专心计算从而造成性能损失 2、 健壮性降低在一个多线程程序里因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的换句话说线程之间是缺乏保护的 在下面这个程序中次线程2 出现异常后会导致整个进程运行异常进而终止进程 #include iostream #include unistd.h #include pthread.husing namespace std;void *threadHandler1(void *args) {while (true){cout 我是次线程1我正在运行... endl;sleep(1);} }void *threadHandler2(void *args) {while (true){sleep(5); // 等其他线程先跑一会cout 我是次线程2我正在运行... endl;char *ps Change World!;*ps N;} }int main() {pthread_t t1, t2; // 创建两个线程pthread_create(t1, NULL, threadHandler1, NULL);pthread_create(t2, NULL, threadHandler2, NULL);// 主线程运行while (true){cout 我是主线程 endl;sleep(1);}return 0; }结果一轮到 次线程2 运行因为触发异常从而整个进程就直接终止了 为什么 单个线程 引发的错误需要让 整个进程 来承担 站在技术角度完全可以让其自行承担但这不合理系统角度线程是进程的执行分支线程出问题了进程也不应该继续运行比如一颗老鼠屎坏了一锅汤信号角度线程出现异常后MMU 识别到异常 - 操作系统将异常转换为信号 - 发送信号给指定进程信号的对象是进程自然无法单发给 线程进而整个进程也就都终止了 3、缺乏访问控制进程是访问控制的基本粒度在一个线程中调用某些OS函数会对整个进程造成影响 如何证明 轻量级线程 看到的是同一份资源通过 多进程中父子进程之间发生写时拷贝的例子验证 #include iostream #include unistd.h #include pthread.husing namespace std;int g_val 0;void *threadHandler1(void *args) {while (true){printf(我是次线程1我正在运行... g_val: %p g_val: %d\n, g_val, g_val);sleep(1);} }void *threadHandler2(void *args) {while (true){printf(我是次线程2我正在运行... g_val: %p g_val: %d\n, g_val, g_val);g_val; // 次线程2 每次都需改这个全局变量sleep(1);} }int main() {pthread_t t1, t2; // 创建两个线程pthread_create(t1, NULL, threadHandler1, NULL);pthread_create(t2, NULL, threadHandler2, NULL);// 主线程运行while (true){printf(我是主线程我正在运行... g_val: %p g_val: %d\n, g_val, g_val);sleep(1);}return 0; }结果无论是主线程还是次线程当其中的一个线程出现修改行为时其他线程也会同步更改 多个线程访问同时访问一个资源不加以保护的话势必会造成影响当然这都是后话了加锁相关内容 4、编程难度提高编写与调试一个多线程程序需要考虑许多问题诸如 加锁、同步、互斥 的等面对多个执行流时调试也是非常困难的 3.4、线程的用途 合理的使用 多线程可以提高 CPU 计算密集型程序的效率 合理的使用 多线程可以提高 IO 密集型程序中用户的体验具体表现为用户可以一边下载一边做其他事情 总结 以上就是本次关于 Linux多线程【初识线程】的全部内容了在本文中我们主要学习了 线程 的基本概念深入理解了地址空间比如 如何页表进行地址的转换最后复盘了 线程 的基本概念学习了其优缺点及使用场景多线程 是一个十分重要的章节需要用心学习 相关文章推荐 Linux进程信号 : 【信号产生】、【信号保存】、【信号处理】 Linux进程间通信 : 【消息队列、信号量】、【共享内存】、【命名管道】、【匿名管道】 Linux基础IO : 【软硬链接与动静态库】、【深入理解文件系统】、【模拟实现C语言文件流】、【重定向及缓冲区理解】、【文件理解与操作】 Linux进程控制 : 【简易版bash】、【进程程序替换】、【创建、终止、等待】 Linux进程学习 : 【进程地址】、【环境变量】、【进程状态】、【基本认知】 Linux基础 : 【gdb】、【git】、【gcc/g】、【vim】、Linux 权限理解和学习、听说Linux基础指令很多这里都帮你总结好了
http://www.dnsts.com.cn/news/133211.html

相关文章:

  • mysql 学习网站做一个网站分析应该怎么做
  • 六安市建设局网站大型企业网站开发
  • php网站开发基础入门教程包含导航栏至少包含三个布局
  • 网站建设优化服务好么网站域名如何起
  • 做网站怎样实现网上支付农村电子商务专业就业方向
  • 在哪里进行网站域名的实名认证有什么做衣服的网站
  • 做网站好做吗北京市重大项目建设指挥部网站
  • 长春网站建设q479185700強深圳高端网站建设公司
  • 国家建设部建筑业网站网站建设框架编写目的
  • 已注册的网站如何注销免费的招聘网站
  • 找人做小程序要多少钱网站文章内容优化方案
  • 怎么看网站被惩罚仿腾讯网站源码
  • 餐饮 网站建设外贸公司网站源码
  • dedecms网站搬家从事网站开发方向
  • 让人做网站需要注意什上海互联网seo公司
  • 静态网页模板免费下载的网站江苏九天建设有限公司网站
  • 商丘做网站的公司自己做鲜花网站怎么样
  • 如何得到网站后台权限公司网站建设山东
  • 深圳外贸网站制作价格WordPress的欢迎页面
  • 网站建设管理和运行维护制度知名网站建设设计
  • 重庆平台网站建设推荐建设了湛江市志愿服务网站
  • 做宣传册模板的网站万网提供的网站建设服务的具体项目
  • 凡科建站案例今天的新闻联播
  • 建设招聘网站需要哪些资质百度广告电话号码
  • php与mysql网站开发...wordpress导航类主题
  • 万州做网站多少钱广西南宁电商网站建设
  • 制作网站工具做网站开发平台
  • 军事热点最新情况有实力seo优化费用
  • 建筑公司网站模板网站建设投标书模板
  • 地方网站用什么域名昆明市住房和城乡建设局门户网站