巧谈GCD

4. dispatch_group

一般用法

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{
    // 异步任务1
});

dispatch_group_async(group, queue, ^{
    // 异步任务2
});

// 等待group中多个异步任务执行完毕,做一些事情,介绍两种方式

// 方式1(不好,会卡住当前线程)
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
...

// 方式2(比较好)
dispatch_group_notify(group, mainQueue, ^{
    // 任务完成后,在主队列中做一些操作
    ...
});

选择场景
上述的一种方法,可以适用于自己维护的有些异步义务的一道问题;可是对于曾经封装好的有的库,比如AFNetworking等,大家不到手其异步任务的行列,那里能够通过一种计数的格局控制职责间协同,上边为化解单界面多接口的一种艺术。

// 两个请求和参数为我项目里面的不用在意。

// 计数+1
dispatch_group_enter(group);
[JDApiService getActivityDetailWithActivityId:self.activityId Location:stockAddressId SuccessBlock:^(NSDictionary *userInfo) {
    // 数据返回后一些处理
    ...

    // 计数-1
    dispatch_group_leave(group);
} FailureBlock:^(NSError *error) {
    // 数据返回后一些处理
    ...

    // 计数-1
    dispatch_group_leave(group);
}];

// 计数+1
dispatch_group_enter(group);
[JDApiService getAllCommentWithActivityId:self.activityId PageSize:3 PageNum:self.commentCurrentPage SuccessBlock:^(NSDictionary *userInfo) {
    // 数据返回后一些处理
    ...

    // 计数-1
    dispatch_group_leave(group);
} FailureBlock:^(NSError *error) {
    // 数据返回后一些处理
    ...

    // 计数-1
    dispatch_group_leave(group);
}];

// 其实用计数的说法可能不太对,但是就这么理解吧。会在计数为0的时候执行dispatch_group_notify的任务。
dispatch_group_notify(group, mainQueue, ^{
    // 一般为回主队列刷新UI
    ...
});
2.2.1 CPU虚拟化技术解决措施
  • 全虚拟化:客户操作系统运行在 Ring
    1,它在实践特权指令时,会触发卓殊,然后
    hypervisor捕获那几个尤其,在卓殊里面做翻译,最后回到到客户操作系统内,客户操作系统认为自己的特权指令工作例行,继续运行。所以也叫二进制翻译技术(Binary
    Translate)。
    然而这一个特性损耗分外的大,简单的一条指令现在却要经过复杂的可怜处理进程
    图片 1

    • 亮点:不用修改GuestOS内核可以直接使用
    • 症结:在VMM捕获特权指令和翻译进度会造成性能的减退。
      图片 2
      从上图可以观望,当虚拟机中的应用要运行在内核态的时候,会通过Hypervisor层的模仿,通过二进制翻译技术,将指令替换为其他的指令。
  • 半虚拟化:修改操作系统内核,替换掉不可能虚拟化的一声令下,通过一级调用(hypercall)直接和底部的虚拟化层hypervisor来报导,
    争论于完全虚拟化性能更高,因为省去了翻译的经过。可是急需对Guest
    OS举行修改,应用场景不多。
    图片 3
  • 硬件支持虚拟化: 二〇〇五年后,CPU厂商速龙 和 英特尔 先导帮助虚拟化了。
    速龙 引入了 英特尔-VT (Virtualization Technology)技术
    首要的已毕格局是增添了一个VMX
    non-root操作格局,运行VM时,客户机OS运行在non-root格局,依旧有Ring0~ring3等级别
    当运行特权指令时抑或暴发中断的时候,通过VM_EXIT就能够切换到root形式,拦截VM对虚拟硬件的拜访。执行完成,通过VM_ENTRY回到non-root即可。
    图片 4
    那种技能主要代表为intel VT-X,AMD的AMD-V
    图片 5

全虚拟化

半虚拟化

硬件辅助虚拟化

实现技术

BT和直接执行

Hypercall

客户操作系统修改/兼容性

无需修改客户操作系统,最佳兼容性

客户操作系统需要修改来支持hypercall,因此它不能运行在物理硬件本身或其他的hypervisor上,兼容性差,不支持Windows

性能

好。半虚拟化下CPU性能开销几乎为0,虚机的性能接近于物理机。

应用厂商

VMware Workstation/QEMU/Virtual PC

Xen

KVM 是基于CPU
扶持的全虚拟化方案,它需求CPU虚拟化特性的帮助。
总结:
图片 6

1. dispatch_async

相似用法

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
    // 一个异步的任务,例如网络请求,耗时的文件操作等等
    ...
    dispatch_async(dispatch_get_main_queue(), ^{
        // UI刷新
        ...
    });
});

动用场景
那种用法格外普遍,比如敞开一个异步的网络请求,待数额重返后回去主队列刷新UI;又比如请求图片,待图片重临刷新UI等等。

2.1 服务器虚拟化架构

  • 裸金属架构:Hypervisor层直接运行在硬件系统上。典型例子是KVM。KVM其实就是Linux内核提供的虚拟化架构,可将根本直接担任Hypervisor,KVM一般需求处理器本身支持虚拟化增添技术,如英特尔VT等。KVM使用内核模块kvm.ko来落到实处要旨虚拟化成效,但是只提供了CPU和内存的虚拟化,必须结合QEMU才能整合完整的虚拟化技术。

图片 7

  • 宿主架构:典型的就是QEMU,它可以透过二进制转换到模拟CPU,使Guest
    OS认为自己再与硬件打交道。
    图片 8

1. 队列

调度队列是一个对象,它会以first-in、first-out的办法管理您提交的天职。GCD有两种队列类型:

  • 串行队列,串行队列将任务以先进先出(FIFO)的逐条来执行,所以串行队列平常用来做访问一些特定资源的共同处理。你可以也依据须求创设多少个连串,而那一个队列相对其他队列都是出新执行的。换句话说,假设你创建了4个串行队列,每一个行列在同一时间都只举行一个职务,对这三个职分的话,他们是并行独立且并发执行的。即便急需创制串行队列,一般用dispatch_queue_create那一个点子来促成,并点名队列类型DISPATCH_QUEUE_SERIAL。
  • 相互队列,并发队列尽管是能同时施行三个义务,但那些职分依旧是按部就班先到先实施(FIFO)的相继来施行的。并发队列会基于系统负荷来适合地拔取并发执行这几个职务。并发队列一般指的就是全局队列(Global
    queue),进程中存在多少个全局队列:高、中(默许)、低、后台七个先行级队列,可以调用dispatch_get_global_queue函数传入优先级来拜会队列。当然大家也可以用dispatch_queue_create,并指定队列类型DISPATCH_QUEUE_CONCURRENT,来自己创办一个冒出队列。
  • 主队列,与主线程功能相同。实际上,提交至main
    queue的任务会在主线程中实施。main
    queue能够调用dispatch_get_main_queue()来赢得。因为main
    queue是与主线程相关的,所以那是一个串行队列。和其余串行队列一样,那一个队列中的任务两遍只能举办一个。它能担保所有的义务都在主线程执行,而主线程是唯一可用来更新
    UI 的线程。

额外说一句,上边也说过,队列间的推行是互为的,不过也设有一些限制。比如,并行执行的行列数量受到内核数的限制,不可能真正完结大量队列并行执行;比如,对于互相队列中的全局队列而言,其设有优先级关系,执行的时候也会按照其事先顺序,而不是并行。

2.4.1 KSM (Kernel SamePage Merging 或者 Kernel Shared Memory)

KSM 是根本中的守护进程(称为
ksmd),它会定期进行页面扫描,将副本页面进行统一,然后释放多余的页面。KVM使用KSM来裁减八个一般的虚拟机的内存占用,升高内存的拔取效用,在虚拟机使用同样镜像和操作系统时,效果更是明白。可是会增添水源开发,所以为了进步成效,可以将此特性关闭。

四、内存和平安

稍微提一下吗,因为部分人纠结于dispatch的内存问题。
内存

  • MRC:用dispatch_retain和dispatch_release管理dispatch_object_t内存。
  • ARC:ARC在编译时刻自动管理dispatch_object_t内存,使用retain和release会报错。

安全
dispatch_queue是线程安全的,你可以擅自往里面添加义务。

2.3.2 通过INTEL EPT技术来落到实处

KVM 中,虚机的情理内存即为 qemu-kvm 进程所占有的内存空间。KVM 使用
CPU 援救的内存虚拟化格局。在 速龙 和 AMD平台,其内存虚拟化的兑现格局分别为:

  • AMD 平台上的 NPT (Nested Page Tables) 技术
  • 速龙 平台上的 EPT (Extended Page Tables)技术
    EPT 和 NPT选拔类似的原理,都是用作 CPU
    中新的一层,通过硬件用来将客户机的大体地址翻译为主机的大体地址。也就是说Guest
    OS落成虚拟机虚拟地址–>虚拟机物理地址第一层转化,硬件同时形成虚拟机物理地址到物理机物理地址那第二层转化。第二层转换对Guest
    OS来说是透明的,Guest
    OS访问内存时和在物理机运行时是同一的。那种办法又称作内存协助虚拟化。

由此内存支持虚拟化就是一贯用硬件来兑现虚拟机的情理地址到宿主机的物理地址的一步到位映射。VMM不用再保留一份
SPT (Shadow Page
Table),通过EPT技术,不再必要一块多个页表,虚拟机内部的切换也不须要qemu进程切换,所急需的是只是三次页表查找,而且是透过硬件来落成的,性能损耗低。

流程如下:

  • VM中的应用发现页没有分片,MMU发起中断,从虚拟机的物理地址(QEMU的逻辑地址)中分配一页,然后更新页表。
    图片 9
  • 那时虚拟机页的物理地址还没对应物理内存的地址,所以触发了qemu进程在宿主机的page
    fault。宿主机内核分配内存页,并创新页表。
    图片 10
  • 下次访问就可以借助EPT来举行,只需求查两回表即可。

图片 11

总结:
图片 12

8. dispatch_semaphore_signal

一般用法

// dispatch_semaphore_signal有两类用法:a、解决同步问题;b、解决有限资源访问(资源为1,即互斥)问题。
// dispatch_semaphore_wait,若semaphore计数为0则等待,大于0则使其减1。
// dispatch_semaphore_signal使semaphore计数加1。

// a、同步问题:输出肯定为1、2、3。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore1 = dispatch_semaphore_create(1);
dispatch_semaphore_t semaphore2 = dispatch_semaphore_create(0);
dispatch_semaphore_t semaphore3 = dispatch_semaphore_create(0);

dispatch_async(queue, ^{
    // 任务1
    dispatch_semaphore_wait(semaphore1, DISPATCH_TIME_FOREVER);
    NSLog(@"1\n");
    dispatch_semaphore_signal(semaphore2);
    dispatch_semaphore_signal(semaphore1);
});

dispatch_async(queue, ^{
    // 任务2
    dispatch_semaphore_wait(semaphore2, DISPATCH_TIME_FOREVER);
    NSLog(@"2\n");
    dispatch_semaphore_signal(semaphore3);
    dispatch_semaphore_signal(semaphore2);
});

dispatch_async(queue, ^{
    // 任务3
    dispatch_semaphore_wait(semaphore3, DISPATCH_TIME_FOREVER);
    NSLog(@"3\n");
    dispatch_semaphore_signal(semaphore3);
});

// b、有限资源访问问题:for循环看似能创建100个异步任务,实质由于信号限制,最多创建10个异步任务。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
for (int i = 0; i < 100; i ++) {
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_async(queue, ^{
    // 任务
    ...
    dispatch_semaphore_signal(semaphore);
    });
}

运用场景
实质上关于dispatch_semaphore_t,并从未看出太多选用和资料表达,我只好参照自己对linux信号量的领悟写了八个用法,经测试确实相似。那里,就不对有的死锁问题举办啄磨了。

2.4.2 KVM Huge Page Backed Memory (巨页内存技术)

速龙 的 x86 CPU 寻常使用4Kb内存页,当是经过安顿,也可以选拔巨页(huge
page): (4MB on x86_32, 2MB on x86_64 and x86_32
PAE)使用巨页,KVM的虚拟机的页表将利用更少的内存,并且将增进CPU的频率。最高意况下,可以增强20%的作用!

5. dispatch_barrier_async

诚如用法

// dispatch_barrier_async的作用可以用一个词概括--承上启下,它保证此前的任务都先于自己执行,此后的任务也迟于自己执行。本例中,任务4会在任务1、2、3都执行完之后执行,而任务5、6会等待任务4执行完后执行。

dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    // 任务1
    ...
});
dispatch_async(queue, ^{
    // 任务2
    ...
});
dispatch_async(queue, ^{
    // 任务3
    ...
});
dispatch_barrier_async(queue, ^{
    // 任务4
    ...
});
dispatch_async(queue, ^{
    // 任务5
    ...
});
dispatch_async(queue, ^{
    // 任务6
    ...
});

运用场景
和dispatch_group类似,dispatch_barrier也是异步义务间的一种共同情势,可以在比如文件的读写操作时接纳,保障读操作的准头。其余,有某些亟待小心,dispatch_barrier_sync和dispatch_barrier_async只在大团结创立的并发队列上有效,在全局(Global)并发队列、串行队列上,效果跟dispatch_(a)sync效果等同。

2.2 CPU虚拟化

进程的举行有三种状态

  • 内核态:紧要用于硬件访问,修改重点参数,
  • 用户态:用户运行应用程序。

三种意况的权位差异,对硬件的拜访必须在内核态,可以保障系统的可信性,只给使用人士开放用户态,不会对OS的运行带来大的影响。幸免系统被人工攻击。

OS内核数据和代码区应该与用户区完全切断,也就是说程序可以看到的地方都是用户态地址,当程序执行系统调用的时候,过程会切入内核态举行基础访问,那儿页表也急需切换来内核态的页表,带来的问题是性质比较差。因为页表在内存中,切换会带来性能的下挫。

故此如今主流的OS的做法是将基本代码和数据区放到用户进程虚拟地址控制器的高位区,32bit系统放到3~4G,windows默许占用2~4G区,64bit系统也位于高位。那样带来的利益是,进度空间的内核区也被映射到大体内存区,进度的切换不会导致TLB中从前缓存的对准内核区页表失效,保障了性能。

实际上进度是不可能访问内核区,因为强行访问的话,页表条目有权限位(进度近日权限保存在寄存器的CPL字段,为Ring3,而基本页表的权杖为Ring0,所以CPU会禁止访问。)

小结一下就是x86 架构提供八个特权级别给操作系统和应用程序来做客硬件。
Ring 是指 CPU 的周转级别,Ring 0是最高级别,Ring1次之,Ring2更次之……

  • 根本需求直接访问硬件和内存,由此它的代码须要周转在最高运行级别
    Ring0上,那样它可以接纳特权指令比如控制中断、修改页表、访问设备等等。
  • 应用程序的代码运行在低于运行级别上Ring3上,怎样要拜访磁盘,那就须要执行系统调用,此时CPU的运行级别会生出从ring3到ring0的切换,并跳转到系统调用对应的基业代码地点执行,那样基本就为你完毕了设备访问,已毕之后再从ring0重临ring3。那个进度也称成效户态和内核态的切换。

图片 13

对于非虚拟化操作系统而言,应用程序和系统发出的日常指令都运作在用户级别指令中,唯有特权指令运行在主导级别中,那样操作系统与利用解耦合。

那就是说,虚拟化在那边就碰见了一个难题,因为物理机OS是做事在 Ring0
的,虚拟机的操作系统就无法也在 Ring0
了,所以有的特权指令是绝非实施权限的

CPU虚拟化的法门就是

  • 特权解除:让Guest
    OS运行在用户级别,让hypervisor运行在宗旨级别,那样就排除了Guest
    OS的特权级别。
  • 陷入模拟:运作在Guest
    OS的平时指令像过去一样运行,当运行到特权指令时,会生出很是并被hypervisor捕获。
    图片 14

那么困难在于:

  • 怎么样模拟x86珍惜情势
  • 如何阻止并施行虚拟机的Ring0指令。
    解决方法如下

三、GCD常见用法和选取场景

至极欣赏一句话:Talk is cheap, show me the
code.接下来对GCD的利用,我会通过代码展示。

第一章 服务器虚拟化概述

二、队列和天职

初学GCD的时候,肯定会纠结一些好像很重大但却毫无意义的题目。比如:GCD和线程到底哪些关系;异步任务到底在哪个线程工作;队列到底是个什么样东西;mian
queue和main
thread到底搞哪样名堂等等。现在,那个大家平昔略过(最后拾遗中会谈一下),苹果既然推荐使用GCD,那么为啥还要纠结于线程呢?须求关爱的唯有多少个概念:队列、职责。

2.3.1 软件方式

黑影页表(SPT,shadow page
table):Hypervisor为虚拟机保证了一个虚拟机的虚拟地址到宿主机大体地址辉映的的页表。也就是说,在原先的两层地址层次基础上加了一层伪物理地址层次,通过那张表可以将客户机虚拟地址宿主机物理地址中间举办映射。

客户OS成立之后,Hypervisor创制其对应影子页表。刚开首影子页表是空的,此时其他客户OS的访存操作都会爆发缺页中断,然后Hypervisor捕获缺页非凡

图片 15

经过一次地址映射转换得到虚拟机虚拟地址物理机物理地址的映照关系,写入黑影页表,逐步到位具有虚拟地址到宿主机机器地址的投射。
图片 16

代价是内需有限扶助虚拟机的页表和宿主机的阴影页表的联合。

7. dispatch_suspend和dispatch_resume

貌似用法

dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_suspend(queue); //暂停队列queue
dispatch_resume(queue);  //恢复队列queue

动用场景
那种用法我还从未尝试过,可是其中有个需求注意的点。那八个函数不会潜移默化到行列中已经履行的职务,队列暂停后,已经添加到队列中但还没有举办的天职不会举办,直到队列被还原。

2.6 网卡虚拟化

VM发出的流量一般有两种

  • 到物理机外部的设施,
  • 到当地物理服务器上的虚拟机。

因此大家须要保障不相同虚拟机流量的相互隔离,同时又要考虑情理设备内虚拟机的互联互通。

解决方法:
对于对物理机外部的流量,给种种VM分配一个专用通道,共享物理网卡资源。
首要有如下两种形式:

  • Bridge桥接形式:把物理主机上的网卡当调换机,然后虚拟出一个Bridge来接收发往物理机的包。
    图片 17
  • isolation mode:仅guest OS之间通讯;不与表面网络和宿主机通讯。
    图片 18
  • routed mode:与表面主机通讯,通过静态路由使得各Guest OS
    的流量需经过物理网卡
    图片 19
  • nat:地址转换;在编造网卡和物理网卡之间确立一个nat转载服务器;对数据包进行源地址转换。
    图片 20

对内部流量:

  • 在hypervisor上确立virtual
    switch,不过会损耗CPU资源,而且存在较大安全隐患。(intel的VT-c用VMDq技术使网卡芯片处理局地vswitch的做事,同时用vFW来有限支撑安全)
  • 可以先让流量出服务器通过安全设备区域展开多少清洗未来再回到。主流格局使用硬件SR-IOV对VM流量举办识别和处理

总结

图片 21

2. 任务

linux内核中的义务的概念是讲述进度的一种结构体,而GCD中的职分只是一个代码块,它可以指一个block或者函数指针。根据那么些代码块添加进去队列的措施,将职务分为同步职务和异步义务:

  • 联机义务,使用dispatch_sync将任务插手队列。将同台义务参与串行队列,会挨个执行,一般不那样做而且在一个义务未竣事时调起其余同步义务会死锁。将协同义务参预并行队列,会相继执行,可是也没怎么意思。
  • 异步义务,使用dispatch_async将职务参预队列。将异步使命参与串行队列,会相继执行,并且不会油可是生死锁问题。将异步义务参与并行队列,会并行执行两个职分,那也是大家最常用的一种办法。

Technorati 标签:
云计算,虚拟化

3. 不难易行利用

// 队列的创建,queue1:中(默认)优先级的全局并行队列、queue2:主队列、queue3:未指定type则为串行队列、queue4:指定串行队列、queue5:指定并行队列
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queue2 = dispatch_get_main_queue();
dispatch_queue_t queue3 = dispatch_queue_create("queue3", NULL);
dispatch_queue_t queue4 = dispatch_queue_create("queue4", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue5 = dispatch_queue_create("queue5", DISPATCH_QUEUE_CONCURRENT);

// 队列中添加异步任务
dispatch_async(queue1, ^{
// 任务
...
});

// 队列中添加同步任务
dispatch_sync(queue1, ^{
// 任务
...
});

1.2 虚拟化发展历史

  • 提议概念:1959年七月提出,在列国新闻处理大会上登载的《大型高速统计机中的时间共享》论文中指出
  • 开发技术:20世纪60年间初始,IBM操作系统虚拟化技术应用在了大型机和袖珍机上
  • 蓬勃发展:20世纪90年份,VMware公司率先落实了X86架构上的虚拟化,于1999年出产了x86平台上的率先款虚拟化商业软件VMware
    workstation。
  • 群雄逐鹿:更加多的厂商投入了虚拟化技术的枪杆子

第二章 服务器虚拟化

服务器虚拟化紧要有二种办法:

  • 硬件虚拟化:通过Hypervisor层虚拟出硬件系统环境,将硬件系统CPU发出的指令经过处理后传到大体CPU上。

硬件虚拟化的关键在于Hypervisor层。

所谓Hypervisor层就是在物理服务器和操作系统中间运行的软件层,可以对模拟硬件系统,将次第对那么些硬件系统CPU发送的吩咐经过处理未来,加以虚拟传到物理CPU上。同时它可以协调访问服务器上的情理设备和虚拟机,也叫虚拟机监视器(VMM
)。

  • 容器:只是虚拟化出利用运行时的环境,是比较轻量的虚拟化,层次相比较浅。

一、四线程背景

Although threads have been around for many years and continue to have
their uses, they do not solve the general problem of executing
multiple tasks in a scalable way. With threads, the burden of creating
a scalable solution rests squarely on the shoulders of you, the
developer. You have to decide how many threads to create and adjust
that number dynamically as system conditions change. Another problem
is that your application assumes most of the costs associated with
creating and maintaining any threads it uses.

上述大致说出了直接操纵线程达成二十四线程的弊病:

  • 开发人士必须依据系统的变动动态调整线程的数目和情状,即对开发者的负担重。
  • 应用程序会在制造和保安线程上消耗过多财力,即效能低。

对峙的,GCD是一套低层级的C API,通过
GCD,开发者只须求向队列中添加一段代码块(block或C函数指针),而不须求直接和线程打交道。GCD在后端管理着一个线程池,它不但控制着你的代码块将在哪个线程被执行,还按照可用的系统资源对这么些线程举行保管。GCD的干活方式,使其负有众多优点(快、稳、准):

  • 快,更快的内存成效,因为线程栈不暂存于应用内存。
  • 稳,提供了机动的和周密的线程池管理机制,稳定而便利。
  • 准,提供了直接并且不难的调用接口,使用方便,准确。

2.5 IO虚拟化

  • 模仿(完全虚拟):使用 QEMU 纯软件的法子来模拟 I/O
    设备。使用一个瑟维斯(Service) VM来模拟真实硬件,性能很差。
    客户机的设施驱动程序发起 I/O
    请求操作请求,KVM会捕获此IO请求,然后嵌入IO共享页,同时用户空间的QEMU进度,QEMU模拟出这一次IO操作,同样置于共享页中并还要KVM进行结果的取回。

瞩目:当客户机通过DMA (Direct Memory Access)访问大块I/O时,QEMU
模拟程序将不会把结果放进共享页中,而是通过内存映射的法门将结果直接写到客户机的内存中,然后文告KVM模块告诉客户机DMA操作已经已毕。

图片 22

  • 半虚拟化: KVM/QEMU就使用那种方式,它在 Guest OS 内核中装置前端驱动
    (Front-end driver)和在 QEMU
    中贯彻后端驱动(Back-end)的主意。前后端驱动通过 vring
    (完结虚拟队列的环形缓冲区)直接通讯,那就绕过了通过 KVM
    内核模块的进度,进步了IO性能,相对于完全虚拟的情势,
    省去了纯模仿格局下的卓殊捕获环节,Guest OS 可以和 QEMU 的 I/O
    模块直接通讯。

图片 23

  • IO-through:直接把机物理设备分配给虚拟机,但是须求硬件具备IO透传技术;,速龙定义的 I/O 虚拟化技术变成 VT-d,AMD 的名叫 英特尔-V。
    KVM 协理客户机以垄断情势访问这些宿主机的 PCI/PCI-E
    设备。通过硬件支撑的 VT-d
    技术将装备分给客户机后,在客户机看来,设备是情理上一连在PCI或者PCI-E总线上的
    差一些所有的 PCI 和 PCI-E
    设备都帮忙直接分配,除了显卡以外(显卡的特殊性在此处)。PCI
    Pass-through 必要硬件平台 速龙 VT-d 或者 英特尔 IOMMU
    的协助。那么些特点必须在 BIOS 中被启用
    图片 24

    • 好处:减弱了 VM-Exit 陷入到 Hypervisor
      的进度,极大地提升了性能,可以完成大约和原生系统一样的特性。而且VT-d
      战胜了 virtio 包容性不佳和 CPU 使用功效较高的题目。
    • 不足:独占设备的话,不可以落到实处设备的共享,费用拉长。
    • 不足的化解方案:(1)在一台物理宿主机上,仅少数 I/O
      如网络性能须求较高的客户机使用
      VT-d直接分配设备,其他的应用纯模仿或者 virtio
      已落得多少个客户机共享同一个配备的目的(2)对于网络I/O的解决办法,可以选拔 SR-IOV
      是一个网卡发生三个独立的杜撰网卡,将每个虚拟网卡分配个一个客户机使用。

总结
图片 25

1. 死锁

dispatch_sync

// 假设这段代码执行于主队列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t mainQueue = dispatch_get_main_queue();

// 在主队列添加同步任务
dispatch_sync(mainQueue, ^{
    // 任务
    ...
});

// 在串行队列添加同步任务 
dispatch_sync(serialQueue, ^{
    // 任务
    ...
    dispatch_sync(serialQueue, ^{
        // 任务
        ...
    });
};

dispatch_apply

// 因为dispatch_apply会卡住当前线程,内部的dispatch_apply会等待外部,外部的等待内部,所以死锁。
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(10, queue, ^(size_t) {
    // 任务
    ...
    dispatch_apply(10, queue, ^(size_t) {
        // 任务
        ...
    });
});

dispatch_barrier
dispatch_barrier_sync在串行队列和大局并行队列之中和dispatch_sync同样的职能,所以需考虑同dispatch_sync一样的死锁问题。

1.1 为啥须求服务器虚拟化

假如物理机上只部署一种工作,资源利用率太低,不便于节省花费。如果说生产区域须求选用物理机来保障平稳,对于开发测试区使用虚拟机不但可以省去有限的物理机资源,还足以快捷上线。

6. dispatch_apply

诚如用法

// for循环做一些事情,输出0123456789
for (int i = 0; i < 10; i ++) {
    NSLog(@"%d", i);
}

// dispatch_apply替换(当且仅当处理顺序对处理结果无影响环境),输出顺序不定,比如1098673452
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*! dispatch_apply函数说明
*
*  @brief  dispatch_apply函数是dispatch_sync函数和Dispatch Group的关联API
*         该函数按指定的次数将指定的Block追加到指定的Dispatch Queue中,并等到全部的处理执行结束
*
*  @param 10    指定重复次数  指定10次
*  @param queue 追加对象的Dispatch Queue
*  @param index 带有参数的Block, index的作用是为了按执行的顺序区分各个Block
*
*/
dispatch_apply(10, queue, ^(size_t index) {
    NSLog(@"%zu", index);
});

使用场景
那么,dispatch_apply有何样用吧,因为dispatch_apply并行的运行机制,功用一般快于for循环的类串行机制(在for一回巡回中的处理任务过多时距离相比大)。比如那可以用来拉取网络数据后提前算出各类控件的高低,幸免绘制时计算,升高表单滑动流畅性,如若用for循环,耗时较多,并且每个表单的数目没有借助关系,所以用dispatch_apply比较好。

2.3 内存虚拟化原理

内存虚拟化指的是共享物理系统内存,动态分配给虚拟机。虚拟机的内存虚拟化很象虚拟内存方式

虚拟内存是电脑连串内存管理的一种技术,目的是让应用程序认为它兼具一而再的可用的内存(一个总是完整的地址空间)。其实就是操作系统将内存资源的虚拟化,屏蔽了内存调用的细节,对应用程序而言,不需求关切内存访问的底细,可以把内存当作线性的内存池。

x86 CPU 都不外乎了一个誉为内存管理的模块MMU(Memory Management Unit)和
TLB(Translation Lookaside Buffer),通过MMU和TLB来优化虚拟内存的特性。

OS将内存依据4KB为单位展开分页,形成虚拟地址和情理地址的映射表。要是OS在物理机上运行,只要OS提供那几个页表,MMU会在访存时自动做虚拟地址(Virtual
address, VA)到大体地址(Physical address, PA)的转载。

唯独假设虚拟机上运行OS,Guest
OS经过地方转化到的“物理地址”实际上是QEMU的逻辑地址,因而还亟需采用软件将其转会为真正物理内存地址

对此OS运行在大体机上的事态

图片 26

若是经过访问内存的时候,发现映射表中还尚无物理内存举办相应。如下图

图片 27

此刻MMU向CPU发出缺页中断,操作系统会按照页表中的外存地址,在外存中找到所缺的一页,将其调入内存。同时更新页表的照射关系。下五遍访问的时候可以直接命中物理内存。

图片 28

对此OS在虚拟机中的情形,进度就要复杂很多。

对于虚拟机内的经过的变换,必要进行两次改换。也就是说首先将选择的逻辑地址转换为虚拟机的大体地址,而那其实是QEMU进度的逻辑地址,所以要映射到实在内存的物理地址还索要做一回转换。

图片 29

  • VA:应用的虚拟地址
  • PA:虚拟机物理地址,也是QEMU进度的逻辑地址
  • MA:物理机的大体地址

可知,KVM
为了在一台机器上运行多少个虚拟机,须要扩张一个新的内存虚拟化层,也就是说,必须虚拟
MMU 来帮忙客户OS,完毕 VA -> PA -> MA 的翻译。

客户操作系统继续控制虚拟地址到客户内存物理地址的映射 (VA ->
PA),不过客户操作系统不能平昔访问实际机器内存,因而VMM
要求担当映射客户物理内存到实际机器内存 (PA -> MA)。

图片 30

VMM 内存虚拟化的完成方式:

  • 软件格局:通过软件完毕内存地址的翻译,比如 Shadow page table
    (影子页表)技术
  • 硬件落成:基于 CPU 的增援虚拟化效能,比如 英特尔 的 NPT 和 速龙 的 EPT
    技术

9. dispatch_set_context、dispatch_get_context和dispatch_set_finalizer_f

貌似用法

// dispatch_set_context、dispatch_get_context是为了向队列中传递上下文context服务的。
// dispatch_set_finalizer_f相当于dispatch_object_t的析构函数。
// 因为context的数据不是foundation对象,所以arc不会自动回收,一般在dispatch_set_finalizer_f中手动回收,所以一般讲上述三个方法绑定使用。

- (void)test
{
    // 几种创建context的方式
    // a、用C语言的malloc创建context数据。
    // b、用C++的new创建类对象。
    // c、用Objective-C的对象,但是要用__bridge等关键字转为Core Foundation对象。

    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    if (queue) {
        // "123"即为传入的context
        dispatch_set_context(queue, "123");
        dispatch_set_finalizer_f(queue, &xigou);
    }
    dispatch_async(queue, ^{
        char *string = dispatch_get_context(queue);
        NSLog(@"%s", string);
    });
}

// 该函数会在dispatch_object_t销毁时调用。
void xigou(void *context)
{
    // 释放context的内存(对应上述abc)

    // a、CFRelease(context);
    // b、free(context);
    // c、delete context;
}

利用场景
dispatch_set_context可以为队列添加上下文数据,但是因为GCD是C语言接口方式的,所以其context参数类型是“void
*”。需利用上述abc二种艺术开创context,并且一般结合dispatch_set_finalizer_f使用,回收context内存。

2.7.1 主流的Hypervisor总结

Hypervisor的类别

KVM

Xen

Hyper-v

ESX/ESXi

内核类型

Linux

Linux(修改)&Nemesis

Windows&Hyper-V

Linux&VMernel

内核

单核

外内核

外内核

混合内核

I/O虚拟化方式

类Service VM Model

Service VM Model

Service VM Model

Monolithic Model

特点

集成在Linux内核中

有被KVM取代之势,性能低于KVM

捆绑Windows Server

技术积累深厚,Vmkernel是核心竞争力

3. GCD和线程的关联

一经你是新手,GCD和线程暂时木有关系。
若是您是一把手,大家做朋友吧。

2.4 KVM其余内存管理技术

谈到iOS多线程,一般都会谈到四种艺术:pthread、NSThread、GCD和NSOperation。其中,苹果推荐也是我们最常常使用的可相信是GCD。对于身为开发者的大家来说,并发从来都很棘手,即使对GCD的精晓不够透彻,那么iOS开发的进度相对不会顺遂。这里,我会从多少个角度浅谈自身对GCD的驾驭。

本文基于网上的素材整理而成。

五、拾遗

此处首要提一下GCD的部分坑和线程的有些题材。

2.7 Hypervisor层的虚拟化达成

操作系统是用户和物理机的接口,也是使用和大体硬件的接口。宗旨作用在于职务调度和硬件抽象。

今非昔比操作系统的最大不相同在于内核。

单内核、混合内核、微内核、外内核的区分
图片 31

  • 单内核:内核所有的效能代码全体都运行在同一个基本空间内,优点是性质性能很高,缺点是设计复杂,稳定性不够好;
  • 微内核:类似C/S服务方式,只有最基础的代码会运作于内核空间,其余的都运行于用户空间,优点是安静高,缺点性能较低;
  • 错落内核:性能与平稳的让步产物,完全由设计者举办用户自定义;
  • 外内核:比微内核越发极端,连硬件抽象工作都提交用户空间,内核只须要确保应用程序访问硬件资源时,硬件是悠闲的

图片 32

2. dispatch_time_t

// dispatch_time_t一般在dispatch_after和dispatch_group_wait等方法里作为参数使用。这里最需要注意的是一些宏的含义。
// NSEC_PER_SEC,每秒有多少纳秒。
// USEC_PER_SEC,每秒有多少毫秒。
// NSEC_PER_USEC,每毫秒有多少纳秒。
// DISPATCH_TIME_NOW 从现在开始
// DISPATCH_TIME_FOREVE 永久

// time为1s的写法
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);

2. dispatch_after

诚如用法

dispatch_queue_t queue= dispatch_get_main_queue();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{
    // 在queue里面延迟执行的一段代码
    ...
});

应用场景
那为我们提供了一个简便的推迟执行的艺术,比如在view加载为止延迟执行一个动画等等。

3. dispatch_once

诚如用法

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只执行一次的任务
    ...
});

使用场景
可以采取其创立一个单例,也可以做一些其余只进行四回的代码,比如做一个只可以点五次的button(好像没啥用)。

六、参考文献

1、https://developer.apple.com/library/mac/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html\#//apple\_ref/doc/uid/TP40008091-CH102-SW2
2、https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD\_libdispatch\_Ref/
3、http://tutuge.me/2015/04/03/something-about-gcd/
4、http://www.jianshu.com/p/85b75c7a6286
5、http://www.jianshu.com/p/d56064507fb8

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注