lin

阅读 / 问答 / 标签

Windows Socket和Linux Socket编程的区别

1)头文件windows下winsock.h/winsock2.hlinux下sys/socket.h错误处理:errno.h其他常用函数的头文件可到命令行下用man指令查询。2)初始化windows下需要用WSAStartuplinux下不需要(很方便),直接可以使用3)关闭socketwindows下closeso

Windows Socket和Linux Socket编程的区别 ZZ

  下面大概分几个方面进行罗列:  Linux要包含  [cpp]  #include<sys/socket.h>  #include<netinet/in.h>  #include<netdb.h>  #include<arpa/inet.h>  等头文件,而windows下则是包含  [cpp]  #include<winsock.h>  。  Linux中socket为整形,Windows中为一个SOCKET。  Linux中关闭socket为close,Windows中为closesocket。  Linux中有变量socklen_t,Windows中直接为int。  因为linux中的socket与普通的fd一样,所以可以在TCP的socket中,发送与接收数据时,直接使用read和write。而windows只能使用recv和send。  设置socet选项,比如设置socket为非阻塞的。Linux下为  [cpp]  flag=fcntl(fd,F_GETFL);  fcntl(fd,F_SETFL,flag|O_NONBLOCK);  ,Windows下为  [cpp]  flag=1;  ioctlsocket(fd,FIONBIO,(unsignedlong*)&flag);  。  当非阻塞socket的TCP连接正在进行时,Linux的错误号为EINPROGRESS,Windows的错误号为WSAEWOULDBLOCK。

Windows Socket和Linux Socket编程的区别

socket相关程序从windows移植到linux下需要注意的 1)头文件windows下winsock.h/winsock2.hlinux下sys/socket.h错误处理:errno.h 其他常用函数的头文件可到命令行下用man指令查询。2)初始化windows下需要用WSAStartuplinux下不需要(很方便),直接可以使用3)关闭socketwindows下closesocket(...)linux下close(...)4)类型windows下SOCKET在linux下为int类型5)绑定地址的结构体名称相同,都是struct sockaddr、struct sockaddr_in,这两者通常转换使用;在Windows下面名称都是大写,而在Linux下为小写常用:Linux下:sockaddr_in destAddr;destAdd.sin_family=AF_INET;destAddr.sin_port=htons(2030);destAddr.sin_addr.s_addr=inet_addr("192.168.1.1");Windows下:SOCKADDR_IN destAddr;destAddr.sin_addr.S_un.S_addr=inet_addr("192.168.1.1");但结构体中成员的名称不同Windows中结构体成员struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8];};struct sockaddr { u_short sa_family; char sa_data[14];}; struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; } S_un;};下面的一些宏可以使windows下的程序移植到linux下(通过类型的重新定义,使代码具有linux和windows下的移植性)[cpp] view plaincopy #ifdef WIN32 typedef int socklen_t; typedef int ssize_t; #endif #ifdef __LINUX__ typedef int SOCKET; typedef unsigned char BYTE; typedef unsigned long DWORD; #define FALSE 0 #define SOCKET_ERROR (-1) #endif [cpp] view plain copy #ifdef WIN32 typedef int socklen_t; typedef int ssize_t; #endif #ifdef __LINUX__ typedef int SOCKET; typedef unsigned char BYTE; typedef unsigned long DWORD; #define FALSE 0 #define SOCKET_ERROR (-1) #endif 6)获取错误码windows下getlasterror()/WSAGetLastError()linux下errno变量7)设置非阻塞windows下ioctlsocket()linux下fcntl() <fcntl.h>8)send函数最后一个参数windows下一般设置为0linux下最好设置为MSG_NOSIGNAL,如果不设置,在发送出错后有可 能会导致程序退出。9)毫秒级时间获取windows下GetTickCount()linux下gettimeofday()10)数据类型的一些转化通用的:小端到大端(网络协议使用)的转换:htonl, htons点分十进制IP和整数之间的相互转换:inet_addr()(该函数将点分十进制转为整数),inet_aton(),inet_ntoa(),inet_pton()(linux下独有 该函数可以实现相互之间的转换)使用到的头文件不相同,linux下用man命令查询。另外注意:linux下使用的套接字为伯克利套接字,因此在select()函数的使用上(第一个参数的设置)也有区别;windows下为了与伯克利套接字匹配,第一个参数是无所谓,一般可设为0;int maxfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!3、多线程多线程: (win)process.h --〉(linux)pthread.h_beginthread --> pthread_create_endthread --> pthread_exit

Linux操作系统下Socket编程地址结构介绍

linux下的网络通信程序,一定要和一个结构打交道,这个结构就是socketaddress。比如bind、connect等等函数都要使用socketaddress结构。理解socketaddress时我们要明白,其实在linux下针对于不同的socketdomain定义了一个通用的地址结构structsockaddr,它的具体定义为:{unsignedshortintsa_family;charsa_data[14];}structsockaddr其中,sa_family为调用socket()函数时的参数domain参数,sa_data为14个字符长度存储。针对于不同domain下的socket,通用地址结构又对应了不同的定义,例如一般的AF_INETdomain下,socketaddress的定义如下:structsockaddr_in{unsignedshortintsin_family;uint16_tsin_port;structin_addrsin_addr;unsignedcharsin_zero[8];//未使用}structin_addr{uint32_ts_addr;}当socket的domain不同于AF_INET时,具体的地址定义又是不同的,但是整个地址结构的大小、容量都是和通用地址结构一致的。

求ZARD出道曲《Good-bye my loneliness》罗马拼音

Zard - Good-bye My Loneliness Kokoro no oku wo anata ni nozokaresouMe wo sorashite mo kizukaresou deKemuru tokai no Rain dropsYuraideita noMata hitori ni naru no ga kowakuteGood-bye my lonelinessAnata no mune ni sotto TendernessTobikomitai noDakara ima wa soba ni itehoshii noDakishimete yume ga kieru mae niTsurenai koi no yukue wa kisetsu makaseItsumo mirai ga ame de mienaiTasumu tokai no Tear dropsOkubyou ni naru noSameta omoi atatametehoshiiGood-bye my lonelinessShinjiteite mo futari FarawayOmoide ni naruDakara ima wa soba ni itehoshii noDakishimete subete wasuresaseteGood-bye my lonelinessShinjiteite mo kitto FarawayOmoide ni naruDakara ima wa ikanai de hoshii noDakishimete yume ga kieru mae ni

在linux下能创建windows 的文件系统吗

保收多少个月

搞开发的和搞编程的为什么更倾向于使用Linux系统,而不是windows?

linux 下的C编程很方便啊,比windows方便

linux入侵windows需要学习哪些技术?

违法的……你要是想学习,去找一些安全研究机构吧。

我想将Linux ldap帐户同步到Windows里面的AD域,怎么做啊?急啊

简单回答是没有的你说问的问题设计到了 操作系统原理,如果有时间,而且也有兴趣,可以去看看这方面的书。其实,操作系统 例如 windows 或者说linux 他们是针对 操作而设计的系统。 而什么是数据库,简单的说就是存储 用户的资料或则信息的系统,典型的你一定知道很多了。而操作系统的所有信息都是储存在注册表中的。你在windows系统中 开始-运行中输入 regedit就可以看到了。里面记录可系统的所有的信息和配置的值。如果你把注册表叫做操作系统的数据库,那也是可以理解的。但是严格的说是不对的。linux系统和windows又是完全不同的,它没有注册表。所有的信息和配置信息全部在linxu的配置文件中和 头文件中。这也是 linux与windows系统的最大的差别,当然,单线成与多线程也是他们的区别了。如果还有什么不明白可以到我的空间给我留言,愿意和你一起研究学习. 请参考

为什么要用Linux做服务器?

高端种子用户comp.os.minix 是类 Unix 内核爱好者/学习者讨论组。这个用户组里的用户理解操作系统原理,具备内核代码的理解,设计能力。Linus 做出 Linux 内核第一版后首先发布到了 comp.os.minix,马上引来了众多爱好者关注并贡献代码,很快得以创建 comp.os.linux。到了92年已经能够运行 X-Window。此后 Linux 内核代码飞速发展,全靠越来越多的内核贡献者加盟。和GNU结盟Linux 从 0.01 开始就要求用户自行安装 GNU 工具。后来选择以 GPL 发行。GPL 虽然在帮助创造更好的商业软件上有些争议。但在保证源代码回馈量上却效果极佳。此时GNU Hurd 遥遥无期,社区迫切需要一个高速迭代,能用的 GPL 操作系统内核。因此 Linux 迅速获得更多用户的支持。不论有心无心,这是第二步成功的推广——提供目标用户无可替代的必需品。同时期的 386BSD, 却因为代码和协议问题,没有获得同样推广的机会。免费的操作系统Linux 内核源代码可以免费下载。大多数 Linux 发布版本,包括 GNU/Linux 的发行版本和商业的发行版本几乎都提供免费下载服务。你可以看下Linux书籍《Linux就该这么学》,了解了Linux之后就有答案了。

如何学习linux?

只是一个供大家参考的学习步骤而已, 也可不需要按照此学习,可根据个人学习方式来学习, (文章末尾有一些学习资料)1、Linux 基础安装Linux操作系统Linux文件系统Linux常用命令Linux启动过程详解熟悉Linux服务能够独立安装Linux操作系统能够熟练使用Linux系统的基本命令认识Linux系统的常用服务安装Linux操作系统Linux基本命令实践设置Linux环境变量定制Linux的服务 Shell 编程基础使用vi编辑文件使用Emacs编辑文件使用其他编辑器2、Shell 编程基础Shell简介认识后台程序Bash编程熟悉Linux系统下的编辑环境熟悉Linux下的各种Shell熟练进行shell编程熟悉vi基本操作熟悉Emacs的基本操作比较不同shell的区别编写一个测试服务器是否连通的shell脚本程序编写一个查看进程是否存在的shell脚本程序编写一个带有循环语句的shell脚本程序3、Linux 下的 C 编程基础linux C语言环境概述Gcc使用方法Gdb调试技术AutoconfAutomakeMakefile代码优化 熟悉Linux系统下的开发环境熟悉Gcc编译器熟悉Makefile规则编写Hello,World程序使用 make命令编译程序编写带有一个循环的程序调试一个有问题的程序4、嵌入式系统开发基础嵌入式系统概述交叉编译配置TFTP服务配置NFS服务下载Bootloader和内核嵌入式Linux应用软件开发流程熟悉嵌入式系统概念以及开发流程建立嵌入式系统开发环境制作cross_gcc工具链编译并下载U-boot编译并下载Linux内核编译并下载Linux应用程序嵌入式系统移植Linux内核代码平台相关代码分析ARM平台介绍平台移植的关键技术移植Linux内核到 ARM平台 了解移植的概念能够移植Linux内核移植Linux2.6内核到 ARM9开发板5、嵌入式 Linux 下串口通信串行I/O的基本概念嵌入式Linux应用软件开发流程Linux系统的文件和设备与文件相关的系统调用配置超级终端和MiniCOM 能够熟悉进行串口通信熟悉文件I/O 编写串口通信程序编写多串口通信程序6、嵌入式系统中多进程程序设计Linux系统进程概述嵌入式系统的进程特点进程操作守护进程相关的系统调用了解Linux系统中进程的概念能够编写多进程程序编写多进程程序编写一个守护进程程序sleep系统调用任务管理、同步与通信 Linux任务概述任务调度管道信号共享内存任务管理 API 了解Linux系统任务管理机制熟悉进程间通信的几种方式熟悉嵌入式Linux中的任务间同步与通信编写一个简单的管道程序实现文件传输编写一个使用共享内存的程序7、嵌入式系统中多线程程序设计线程的基础知识多线程编程方法线程应用中的同步问题了解线程的概念能够编写简单的多线程程序编写一个多线程程序8、嵌入式 Linux 网络编程网络基础知识嵌入式Linux中TCP/IP网络结构socket 编程常用 API函数分析Ping命令的实现基本UDP套接口编程许可证管理PPP协议GPRS 了解嵌入式Linux网络体系结构能够进行嵌入式Linux环境下的socket 编程熟悉UDP协议、PPP协议熟悉GPRS 使用socket 编写代理服务器使用socket 编写路由器编写许可证服务器指出TCP和UDP的优缺点编写一个web服务器编写一个运行在 ARM平台的网络播放器9、GUI 程序开发GUI基础嵌入式系统GUI类型编译QT进行QT开发熟悉嵌入式系统常用的GUI能够进行QT编程使用QT编写“Hello,World”程序调试一个加入信号/槽的实例通过重载QWidget 类方法处理事件10、Linux 字符设备驱动程序设备驱动程序基础知识Linux系统的模块字符设备驱动分析fs_operation结构加载驱动程序了解设备驱动程序的概念了解Linux字符设备驱动程序结构能够编写字符设备驱动程序编写Skull驱动编写键盘驱动编写I/O驱动分析一个看门狗驱动程序对比Linux2.6内核与2.4内核中字符设备驱动的不同Linux 块设备驱动程序块设备驱动程序工作原理典型的块设备驱动程序分析块设备的读写请求队列了解Linux块设备驱动程序结构能够编写简单的块设备驱动程序比较字符设备与块设备的异同编写MMC卡驱动程序分析一个文件系统对比Linux2.6内核与2.4内核中块设备驱动的不同11、文件系统虚拟文件系统文件系统的建立ramfs内存文件系统proc文件系统devfs 文件系统MTD技术简介MTD块设备初始化MTD块设备的读写操作了解Linux系统的文件系统了解嵌入式Linux的文件系统了解MTD技术能够编写简单的文件系统为 ARM9开发板添加 MTD支持移植JFFS2文件系统通过proc文件系统修改操作系统参数分析romfs 文件系统源代码创建一个cramfs 文件系统

如何使用simulink建立rbf神经网络建模

  您好,我来为您解答:  使用simulink建立rbf神经网络建模是一彷论文的题目,你去百度文库搜一下,有下载的,全文太长了,我就不复制了。  如果我的回答没能帮助您,请继续追问。

Linux下实现sax解析xml

python能实现。是否可以私聊帮忙?

decline 和 shrink 的区别?

decline降低;shrink缩减,减少,carbon footprint碳排放量降低指的是程度, 减少一般指的是具体数量。故该题答案应该选B.

电话机上的英文line是什么意思

line 英[lau026an] 美[lau026an] n. 线条; 排; 行列; 界线; vt. 排队; 用线标出; 沿…排列成行; 给…安衬里; vi. 形成一层; 排队; 击出平直球; [例句]Draw a line down that page"s center.沿那一页的中心画一条竖线。[其他] 第三人称单数:lines 复数:lines 现在分词:lining 过去式:lined过去分词:lined

simulink 里的频谱仪在哪?

Spectrum Analyzer

请问一下下面这张奥力通行车控制回路图纸中,SI S2 回路中HIN LIN是什么电气元件及其动作原理 谢谢

图纸不全H应该是“高”L应该是“低”HIN“高”输入信号LIN“低”输入信号具体是什么,结合现场

如何在linux下安装ssl证书?

提前Gworg申请好SSL证书,然后根据一下说明安装。解释原因:linux主要分为:Apache、Nginx、Tomcat,三种类型,安装方式各有不同。确定好服务器环境后在Gworg查看技术文档进行安装SSL证书。解决办法:可根据Gworg文档安装。ApacheNginxTomcat

Bubblin Up 歌词

歌曲名:Bubblin Up歌手:Dr. Hook专辑:BankruptBlue - BubblinBest Of BlueI think you"re about it about itNo man could ever doubt itYou"re looking so deliciousCould this be the night that we uuuuhGet closer just a littleTake it up another levelLook, it"s just plain and simpleCould this be the night that we uuuuhDon"t fight it, can"t hide itLet"s ride thisIt just feels so rightUuuu, you got the perfect bodyLove the way you"re shakin it for meCan we take it upstairs from the lobbyI don"t see nothing inYou and me bubblin"How do we get startedHow do we get privateOnce we get insideIt"s gonna be troublin"You and me bubblin"Why don"t we get this poppin"Top floor with no disturbingRoom service in the morningThis will be the night that we uuuhElevator"s waiting openDon"t you think it"s time we go inCan"t keep the penthouse waitingThis will be the night that we uuuhClock"s tickin", time"s wastingAnd you"re amazingThis just feels so rightUuuu, you got the perfect bodyLove the way you"re shakin it for meCan we take it upstairs from the lobbyI don"t see nothing inYou and me bubblin"How do we get startedHow do we get privateOnce we get insideIt"s gonna be troublin"You and me bubblin"Got a body like woahWhy you waiting over there let"s rollTake it all the way to the top floorand let"s get bubblin", girl, bubblin" girlGot a body like woahWhy you waiting over there let"s rollTake it all the way to the top floorand let"s get bubblin", girl, bubblin" girlOoh, woo.Uuuu, you got the perfect bodyLove the way you"re shakin it for meCan we take it upstairs from the lobbyI don"t see nothing inYou and me bubblin"How do we get startedHow do we get privateOnce we get insideIt"s gonna be troublin"You and me bubblin"http://music.baidu.com/song/2600558

Linux编译C++文件,说没有找到头文件,怎么啊?新手,不太会用

头文件换一换看看#include <iostream>

simulink打开时报iostreamstreamerro

simulink打开时报iostreamstreamerro方法如下:1、检查MATLAB的环境变量配置是否正确。请检查您的MATLAB根目录下的bin文件夹是否已添加到系统环境变量中。2、重新安装MATLAB并确保安装过程中没有出现任何错误。请注意,在安装过程中不要更改默认的安装路径。3、在MATLAB命令窗口中输入"rehashtoolboxcache"命令并回车,等待一段时间后再尝试打开simulink。4、以上方法无法解决问题,请联系MATLAB官方技术支持或者相关技术人员协助解决。

linux 脚本编程 定时关闭和打开程序

我要开机运行mjpg-streamer/start_uvc_yuv.sh,但是我在/etc/init.d中的的rcS中加入/etc/rc.d/init.d/mjpg_streamer startecho " " > /dev/tty1echo "Starting mjpg-streamer..." > /dev/tty1然后在/etc/rc.d/init.d下创建了mjpg_streamer脚本,写入#!/bin/shbase=start_uvc_yuv.sh# See how we were called.case "$1" instart)/mjpg-streamer/$base;;stop)pid=`/bin/pidof $base`if [ -n "$pid" ]; thenkill -9 $pidfi;;esacexit 0之后我重新启动开发板,start_uvc_yuv.sh脚本并没有运行,而且打印出/mjpg-streamer/start_uvc_yuv.sh: line 30: ./mjpg_streamer: not found举个例子,例如:每天晚上8点自动删除/root/febhost/dat和/root/febhost/log下的文件。脚本怎样编写?

Linux系统如何开机启动自己写的服务

把执行命令写进/etc/rc.local

音箱上有3.5立体声输入口和RCA左右R·L两个输入口,请问我使用3.5MM转3.5MM音频线连接MP3上的Line-out输出

只是存在形式的不同,RCA为两口插头,红色代表左声道,白色为右声道,3.5(AUX口)同样为立体声接头,虽然它只有一个端口,同样也具有左右声道分开传输的功能(在3.5接头上你可以看到两条圈圈形状的线,那就是代表左右声道的信号传输),而如果以音频性能而论两者不存在很大的差别,都是同个档次的东东。模拟信号传输的话,首推卡农口,全平衡,等方式,抗干扰能力要强于RCA和3.5

邪恶力量里的misha collins 在国外人气高吗??

推特粉1026225你说高不高。。。。

热血无赖里BLIND FIRE SHOTS 什么意思?

盲目射击,就是没有按住右键哪种瞄准方面直接射击。你用左键一直开就是哪个了。另外这个也有算你躲藏在掩体后面,沈威直接扫射的哪个动作。

如何提高Linux下块设备IO的整体性能

前言:本文主要讲解Linux IO调度层的三种模式:cfp、deadline和noop,并给出各自的优化和适用场景建议。IO调度发生在Linux内核的IO调度层。这个层次是针对Linux的整体IO层次体系来说的。从read()或者write()系统调用的角度来说,Linux整体IO体系可以分为七层,它们分别是:VFS层: 虚拟文件系统层。由于内核要跟多种文件系统打交道,而每一种文件系统所实现的数据结构和相关方法都可能不尽相同,所以,内核抽象了这一层,专门用来适配各种文件系统,并对外提供统一操作接口。文件系统层: 不同的文件系统实现自己的操作过程,提供自己特有的特征,具体不多说了,大家愿意的话自己去看代码即可。页缓存层: 负责真对page的缓存。通用块层: 由于绝大多数情况的io操作是跟块设备打交道,所以Linux在此提供了一个类似vfs层的块设备操作抽象层。下层对接各种不同属性的块设备,对上提供统一的Block IO请求标准。IO调度层 :因为绝大多数的块设备都是类似磁盘这样的设备,所以有必要根据这类设备的特点以及应用的不同特点来设置一些不同的调度算法和队列。以便在不同的应用环境下有针对性的提高磁盘的读写效率,这里就是大名鼎鼎的Linux电梯所起作用的地方。针对机械硬盘的各种调度方法就是在这实现的。块设备驱动层: 驱动层对外提供相对比较高级的设备操作接口,往往是C语言的,而下层对接设备本身的操作方法和规范。块设备层: 这层就是具体的物理设备了,定义了各种真对设备操作方法和规范。有一个已经整理好的[Linux IO结构图],非常经典,一图胜千言:我们今天要研究的内容主要在IO调度这一层。它要解决的核心问题是,如何提高块设备IO的整体性能?这一层也主要是针对机械硬盘结构而设计的。众所周知,机械硬盘的存储介质是磁盘,磁头在盘片上移动进行磁道寻址,行为类似播放一张唱片。这种结构的特点是,顺序访问时吞吐量较高,但是如果一旦对盘片有随机访问,那么大量的时间都会浪费在磁头的移动上,这时候就会导致每次IO的响应时间变长,极大的降低IO的响应速度。磁头在盘片上寻道的操作,类似电梯调度,实际上在最开始的时期,Linux把这个算法命名为Linux电梯算法,即:如果在寻道的过程中,能把顺序路过的相关磁道的数据请求都“顺便”处理掉,那么就可以在比较小影响响应速度的前提下,提高整体IO的吞吐量。这就是我们为什么要设计IO调度算法的原因。目前在内核中默认开启了三种算法/模式:noop,cfq和deadline。严格算应该是两种:因为第一种叫做noop,就是空操作调度算法,也就是没有任何调度操作,并不对io请求进行排序,仅仅做适当的io合并的一个fifo队列。目前内核中默认的调度算法应该是cfq,叫做完全公平队列调度。这个调度算法人如其名,它试图给所有进程提供一个完全公平的IO操作环境。注:请大家一定记住这个词语,cfq,完全公平队列调度,不然下文就没法看了。cfq为每个进程创建一个同步IO调度队列,并默认以时间片和请求数限定的方式分配IO资源,以此保证每个进程的IO资源占用是公平的,cfq还实现了针对进程级别的优先级调度,这个我们后面会详细解释。查看和修改IO调度算法的方法是:cfq是通用服务器比较好的IO调度算法选择,对桌面用户也是比较好的选择。但是对于很多IO压力较大的场景就并不是很适应,尤其是IO压力集中在某些进程上的场景。因为这种场景我们需要更多的满足某个或者某几个进程的IO响应速度,而不是让所有的进程公平的使用IO,比如数据库应用。deadline调度(最终期限调度)就是更适合上述场景的解决方案。deadline实现了四个队列:其中两个分别处理正常read和write,按扇区号排序,进行正常io的合并处理以提高吞吐量。因为IO请求可能会集中在某些磁盘位置,这样会导致新来的请求一直被合并,可能会有其他磁盘位置的io请求被饿死。另外两个处理超时read和write的队列,按请求创建时间排序,如果有超时的请求出现,就放进这两个队列,调度算法保证超时(达到最终期限时间)的队列中的请求会优先被处理,防止请求被饿死。不久前,内核还是默认标配四种算法,还有一种叫做as的算法(Anticipatory scheduler),预测调度算法。一个高大上的名字,搞得我一度认为Linux内核都会算命了。结果发现,无非是在基于deadline算法做io调度的之前等一小会时间,如果这段时间内有可以合并的io请求到来,就可以合并处理,提高deadline调度的在顺序读写情况下的数据吞吐量。其实这根本不是啥预测,我觉得不如叫撞大运调度算法,当然这种策略在某些特定场景差效果不错。但是在大多数场景下,这个调度不仅没有提高吞吐量,还降低了响应速度,所以内核干脆把它从默认配置里删除了。毕竟Linux的宗旨是实用,而我们也就不再这个调度算法上多费口舌了。1、cfq:完全公平队列调度cfq是内核默认选择的IO调度队列,它在桌面应用场景以及大多数常见应用场景下都是很好的选择。如何实现一个所谓的完全公平队列(Completely Fair Queueing)?首先我们要理解所谓的公平是对谁的公平?从操作系统的角度来说,产生操作行为的主体都是进程,所以这里的公平是针对每个进程而言的,我们要试图让进程可以公平的占用IO资源。那么如何让进程公平的占用IO资源?我们需要先理解什么是IO资源。当我们衡量一个IO资源的时候,一般喜欢用的是两个单位,一个是数据读写的带宽,另一个是数据读写的IOPS。带宽就是以时间为单位的读写数据量,比如,100Mbyte/s。而IOPS是以时间为单位的读写次数。在不同的读写情境下,这两个单位的表现可能不一样,但是可以确定的是,两个单位的任何一个达到了性能上限,都会成为IO的瓶颈。从机械硬盘的结构考虑,如果读写是顺序读写,那么IO的表现是可以通过比较少的IOPS达到较大的带宽,因为可以合并很多IO,也可以通过预读等方式加速数据读取效率。当IO的表现是偏向于随机读写的时候,那么IOPS就会变得更大,IO的请求的合并可能性下降,当每次io请求数据越少的时候,带宽表现就会越低。从这里我们可以理解,针对进程的IO资源的主要表现形式有两个: 进程在单位时间内提交的IO请求个数和进程占用IO的带宽。其实无论哪个,都是跟进程分配的IO处理时间长度紧密相关的。有时业务可以在较少IOPS的情况下占用较大带宽,另外一些则可能在较大IOPS的情况下占用较少带宽,所以对进程占用IO的时间进行调度才是相对最公平的。即,我不管你是IOPS高还是带宽占用高,到了时间咱就换下一个进程处理,你爱咋样咋样。所以,cfq就是试图给所有进程分配等同的块设备使用的时间片,进程在时间片内,可以将产生的IO请求提交给块设备进行处理,时间片结束,进程的请求将排进它自己的队列,等待下次调度的时候进行处理。这就是cfq的基本原理。当然,现实生活中不可能有真正的“公平”,常见的应用场景下,我们很肯能需要人为的对进程的IO占用进行人为指定优先级,这就像对进程的CPU占用设置优先级的概念一样。所以,除了针对时间片进行公平队列调度外,cfq还提供了优先级支持。每个进程都可以设置一个IO优先级,cfq会根据这个优先级的设置情况作为调度时的重要参考因素。优先级首先分成三大类:RT、BE、IDLE,它们分别是实时(Real Time)、最佳效果(Best Try)和闲置(Idle)三个类别,对每个类别的IO,cfq都使用不同的策略进行处理。另外,RT和BE类别中,分别又再划分了8个子优先级实现更细节的QOS需求,而IDLE只有一个子优先级。另外,我们都知道内核默认对存储的读写都是经过缓存(buffer/cache)的,在这种情况下,cfq是无法区分当前处理的请求是来自哪一个进程的。只有在进程使用同步方式(sync read或者sync wirte)或者直接IO(Direct IO)方式进行读写的时候,cfq才能区分出IO请求来自哪个进程。所以,除了针对每个进程实现的IO队列以外,还实现了一个公共的队列用来处理异步请求。当前内核已经实现了针对IO资源的cgroup资源隔离,所以在以上体系的基础上,cfq也实现了针对cgroup的调度支持。总的来说,cfq用了一系列的数据结构实现了以上所有复杂功能的支持,大家可以通过源代码看到其相关实现,文件在源代码目录下的block/cfq-iosched.c。1.1 cfq设计原理在此,我们对整体数据结构做一个简要描述:首先,cfq通过一个叫做cfq_data的数据结构维护了整个调度器流程。在一个支持了cgroup功能的cfq中,全部进程被分成了若干个contral group进行管理。每个cgroup在cfq中都有一个cfq_group的结构进行描述,所有的cgroup都被作为一个调度对象放进一个红黑树中,并以vdisktime为key进行排序。vdisktime这个时间纪录的是当前cgroup所占用的io时间,每次对cgroup进行调度时,总是通过红黑树选择当前vdisktime时间最少的cgroup进行处理,以保证所有cgroups之间的IO资源占用“公平”。当然我们知道,cgroup是可以对blkio进行资源比例分配的,其作用原理就是,分配比例大的cgroup占用vdisktime时间增长较慢,分配比例小的vdisktime时间增长较快,快慢与分配比例成正比。这样就做到了不同的cgroup分配的IO比例不一样,并且在cfq的角度看来依然是“公平“的。选择好了需要处理的cgroup(cfq_group)之后,调度器需要决策选择下一步的service_tree。service_tree这个数据结构对应的都是一系列的红黑树,主要目的是用来实现请求优先级分类的,就是RT、BE、IDLE的分类。每一个cfq_group都维护了7个service_trees,其定义如下:其中service_tree_idle就是用来给IDLE类型的请求进行排队用的红黑树。而上面二维数组,首先第一个维度针对RT和BE分别各实现了一个数组,每一个数组中都维护了三个红黑树,分别对应三种不同子类型的请求,分别是:SYNC、SYNC_NOIDLE以及ASYNC。我们可以认为SYNC相当于SYNC_IDLE并与SYNC_NOIDLE对应。idling是cfq在设计上为了尽量合并连续的IO请求以达到提高吞吐量的目的而加入的机制,我们可以理解为是一种“空转”等待机制。空转是指,当一个队列处理一个请求结束后,会在发生调度之前空等一小会时间,如果下一个请求到来,则可以减少磁头寻址,继续处理顺序的IO请求。为了实现这个功能,cfq在service_tree这层数据结构这实现了SYNC队列,如果请求是同步顺序请求,就入队这个service tree,如果请求是同步随机请求,则入队SYNC_NOIDLE队列,以判断下一个请求是否是顺序请求。所有的异步写操作请求将入队ASYNC的service tree,并且针对这个队列没有空转等待机制。此外,cfq还对SSD这样的硬盘有特殊调整,当cfq发现存储设备是一个ssd硬盘这样的队列深度更大的设备时,所有针对单独队列的空转都将不生效,所有的IO请求都将入队SYNC_NOIDLE这个service tree。每一个service tree都对应了若干个cfq_queue队列,每个cfq_queue队列对应一个进程,这个我们后续再详细说明。cfq_group还维护了一个在cgroup内部所有进程公用的异步IO请求队列,其结构如下:异步请求也分成了RT、BE、IDLE这三类进行处理,每一类对应一个cfq_queue进行排队。BE和RT也实现了优先级的支持,每一个类型有IOPRIO_BE_NR这么多个优先级,这个值定义为8,数组下标为0-7。我们目前分析的内核代码版本为Linux 4.4,可以看出,从cfq的角度来说,已经可以实现异步IO的cgroup支持了,我们需要定义一下这里所谓异步IO的含义,它仅仅表示从内存的buffer/cache中的数据同步到硬盘的IO请求,而不是aio(man 7 aio)或者linux的native异步io以及libaio机制,实际上这些所谓的“异步”IO机制,在内核中都是同步实现的(本质上冯诺伊曼计算机没有真正的“异步”机制)。我们在上面已经说明过,由于进程正常情况下都是将数据先写入buffer/cache,所以这种异步IO都是统一由cfq_group中的async请求队列处理的。那么为什么在上面的service_tree中还要实现和一个ASYNC的类型呢?这当然是为了支持区分进程的异步IO并使之可以“完全公平”做准备喽。实际上在最新的cgroup v2的blkio体系中,内核已经支持了针对buffer IO的cgroup限速支持,而以上这些可能容易混淆的一堆类型,都是在新的体系下需要用到的类型标记。新体系的复杂度更高了,功能也更加强大,但是大家先不要着急,正式的cgroup v2体系,在Linux 4.5发布的时候会正式跟大家见面。我们继续选择service_tree的过程,三种优先级类型的service_tree的选择就是根据类型的优先级来做选择的,RT优先级最高,BE其次,IDLE最低。就是说,RT里有,就会一直处理RT,RT没了再处理BE。每个service_tree对应一个元素为cfq_queue排队的红黑树,而每个cfq_queue就是内核为进程(线程)创建的请求队列。每一个cfq_queue都会维护一个rb_key的变量,这个变量实际上就是这个队列的IO服务时间(service time)。这里还是通过红黑树找到service time时间最短的那个cfq_queue进行服务,以保证“完全公平”。选择好了cfq_queue之后,就要开始处理这个队列里的IO请求了。这里的调度方式基本跟deadline类似。cfq_queue会对进入队列的每一个请求进行两次入队,一个放进fifo中,另一个放进按访问扇区顺序作为key的红黑树中。默认从红黑树中取请求进行处理,当请求的延时时间达到deadline时,就从红黑树中取等待时间最长的进行处理,以保证请求不被饿死。这就是整个cfq的调度流程,当然其中还有很多细枝末节没有交代,比如合并处理以及顺序处理等等。1.2 cfq的参数调整理解整个调度流程有助于我们决策如何调整cfq的相关参数。所有cfq的可调参数都可以在/sys/class/block/sda/queue/iosched/目录下找到,当然,在你的系统上,请将sda替换为相应的磁盘名称。我们来看一下都有什么:这些参数部分是跟机械硬盘磁头寻道方式有关的,如果其说明你看不懂,请先补充相关知识:back_seek_max:磁头可以向后寻址的最大范围,默认值为16M。back_seek_penalty:向后寻址的惩罚系数。这个值是跟向前寻址进行比较的。以上两个是为了防止磁头寻道发生抖动而导致寻址过慢而设置的。基本思路是这样,一个io请求到来的时候,cfq会根据其寻址位置预估一下其磁头寻道成本。设置一个最大值back_seek_max,对于请求所访问的扇区号在磁头后方的请求,只要寻址范围没有超过这个值,cfq会像向前寻址的请求一样处理它。再设置一个评估成本的系数back_seek_penalty,相对于磁头向前寻址,向后寻址的距离为1/2(1/back_seek_penalty)时,cfq认为这两个请求寻址的代价是相同。这两个参数实际上是cfq判断请求合并处理的条件限制,凡事复合这个条件的请求,都会尽量在本次请求处理的时候一起合并处理。fifo_expire_async:设置异步请求的超时时间。同步请求和异步请求是区分不同队列处理的,cfq在调度的时候一般情况都会优先处理同步请求,之后再处理异步请求,除非异步请求符合上述合并处理的条件限制范围内。当本进程的队列被调度时,cfq会优先检查是否有异步请求超时,就是超过fifo_expire_async参数的限制。如果有,则优先发送一个超时的请求,其余请求仍然按照优先级以及扇区编号大小来处理。fifo_expire_sync:这个参数跟上面的类似,区别是用来设置同步请求的超时时间。slice_idle:参数设置了一个等待时间。这让cfq在切换cfq_queue或service tree的时候等待一段时间,目的是提高机械硬盘的吞吐量。一般情况下,来自同一个cfq_queue或者service tree的IO请求的寻址局部性更好,所以这样可以减少磁盘的寻址次数。这个值在机械硬盘上默认为非零。当然在固态硬盘或者硬RAID设备上设置这个值为非零会降低存储的效率,因为固态硬盘没有磁头寻址这个概念,所以在这样的设备上应该设置为0,关闭此功能。group_idle:这个参数也跟上一个参数类似,区别是当cfq要切换cfq_group的时候会等待一段时间。在cgroup的场景下,如果我们沿用slice_idle的方式,那么空转等待可能会在cgroup组内每个进程的cfq_queue切换时发生。这样会如果这个进程一直有请求要处理的话,那么直到这个cgroup的配额被耗尽,同组中的其它进程也可能无法被调度到。这样会导致同组中的其它进程饿死而产生IO性能瓶颈。在这种情况下,我们可以将slice_idle = 0而group_idle = 8。这样空转等待就是以cgroup为单位进行的,而不是以cfq_queue的进程为单位进行,以防止上述问题产生。low_latency:这个是用来开启或关闭cfq的低延时(low latency)模式的开关。当这个开关打开时,cfq将会根据target_latency的参数设置来对每一个进程的分片时间(slice time)进行重新计算。这将有利于对吞吐量的公平(默认是对时间片分配的公平)。关闭这个参数(设置为0)将忽略target_latency的值。这将使系统中的进程完全按照时间片方式进行IO资源分配。这个开关默认是打开的。我们已经知道cfq设计上有“空转”(idling)这个概念,目的是为了可以让连续的读写操作尽可能多的合并处理,减少磁头的寻址操作以便增大吞吐量。如果有进程总是很快的进行顺序读写,那么它将因为cfq的空转等待命中率很高而导致其它需要处理IO的进程响应速度下降,如果另一个需要调度的进程不会发出大量顺序IO行为的话,系统中不同进程IO吞吐量的表现就会很不均衡。就比如,系统内存的cache中有很多脏页要写回时,桌面又要打开一个浏览器进行操作,这时脏页写回的后台行为就很可能会大量命中空转时间,而导致浏览器的小量IO一直等待,让用户感觉浏览器运行响应速度变慢。这个low_latency主要是对这种情况进行优化的选项,当其打开时,系统会根据target_latency的配置对因为命中空转而大量占用IO吞吐量的进程进行限制,以达到不同进程IO占用的吞吐量的相对均衡。这个开关比较合适在类似桌面应用的场景下打开。target_latency:当low_latency的值为开启状态时,cfq将根据这个值重新计算每个进程分配的IO时间片长度。quantum:这个参数用来设置每次从cfq_queue中处理多少个IO请求。在一个队列处理事件周期中,超过这个数字的IO请求将不会被处理。这个参数只对同步的请求有效。slice_sync:当一个cfq_queue队列被调度处理时,它可以被分配的处理总时间是通过这个值来作为一个计算参数指定的。公式为:time_slice = slice_sync + (slice_sync/5 * (4 - prio))。这个参数对同步请求有效。slice_async:这个值跟上一个类似,区别是对异步请求有效。slice_async_rq:这个参数用来限制在一个slice的时间范围内,一个队列最多可以处理的异步请求个数。请求被处理的最大个数还跟相关进程被设置的io优先级有关。1.3 cfq的IOPS模式我们已经知道,默认情况下cfq是以时间片方式支持的带优先级的调度来保证IO资源占用的公平。高优先级的进程将得到更多的时间片长度,而低优先级的进程时间片相对较小。当我们的存储是一个高速并且支持NCQ(原生指令队列)的设备的时候,我们最好可以让其可以从多个cfq队列中处理多路的请求,以便提升NCQ的利用率。此时使用时间片的分配方式分配资源就显得不合时宜了,因为基于时间片的分配,同一时刻最多能处理的请求队列只有一个。这时,我们需要切换cfq的模式为IOPS模式。切换方式很简单,就是将slice_idle=0即可。内核会自动检测你的存储设备是否支持NCQ,如果支持的话cfq会自动切换为IOPS模式。另外,在默认的基于优先级的时间片方式下,我们可以使用ionice命令来调整进程的IO优先级。进程默认分配的IO优先级是根据进程的nice值计算而来的,计算方法可以在man ionice中看到,这里不再废话。2、deadline:最终期限调度deadline调度算法相对cfq要简单很多。其设计目标是:在保证请求按照设备扇区的顺序进行访问的同时,兼顾其它请求不被饿死,要在一个最终期限前被调度到。我们知道磁头对磁盘的寻道是可以进行顺序访问和随机访问的,因为寻道延时时间的关系,顺序访问时IO的吞吐量更大,随机访问的吞吐量小。如果我们想为一个机械硬盘进行吞吐量优化的话,那么就可以让调度器按照尽量复合顺序访问的IO请求进行排序,之后请求以这样的顺序发送给硬盘,就可以使IO的吞吐量更大。但是这样做也有另一个问题,就是如果此时出现了一个请求,它要访问的磁道离目前磁头所在磁道很远,应用的请求又大量集中在目前磁道附近。导致大量请求一直会被合并和插队处理,而那个要访问比较远磁道的请求将因为一直不能被调度而饿死。deadline就是这样一种调度器,能在保证IO最大吞吐量的情况下,尽量使远端请求在一个期限内被调度而不被饿死的调度器。

如何提高Linux下块设备IO的整体性能

前言:本文主要讲解Linux IO调度层的三种模式:cfp、deadline和noop,并给出各自的优化和适用场景建议。IO调度发生在Linux内核的IO调度层。这个层次是针对Linux的整体IO层次体系来说的。从read()或者write()系统调用的角度来说,Linux整体IO体系可以分为七层,它们分别是:VFS层: 虚拟文件系统层。由于内核要跟多种文件系统打交道,而每一种文件系统所实现的数据结构和相关方法都可能不尽相同,所以,内核抽象了这一层,专门用来适配各种文件系统,并对外提供统一操作接口。文件系统层: 不同的文件系统实现自己的操作过程,提供自己特有的特征,具体不多说了,大家愿意的话自己去看代码即可。页缓存层: 负责真对page的缓存。通用块层: 由于绝大多数情况的io操作是跟块设备打交道,所以Linux在此提供了一个类似vfs层的块设备操作抽象层。下层对接各种不同属性的块设备,对上提供统一的Block IO请求标准。IO调度层 :因为绝大多数的块设备都是类似磁盘这样的设备,所以有必要根据这类设备的特点以及应用的不同特点来设置一些不同的调度算法和队列。以便在不同的应用环境下有针对性的提高磁盘的读写效率,这里就是大名鼎鼎的Linux电梯所起作用的地方。针对机械硬盘的各种调度方法就是在这实现的。块设备驱动层: 驱动层对外提供相对比较高级的设备操作接口,往往是C语言的,而下层对接设备本身的操作方法和规范。块设备层: 这层就是具体的物理设备了,定义了各种真对设备操作方法和规范。有一个已经整理好的[Linux IO结构图],非常经典,一图胜千言:我们今天要研究的内容主要在IO调度这一层。它要解决的核心问题是,如何提高块设备IO的整体性能?这一层也主要是针对机械硬盘结构而设计的。众所周知,机械硬盘的存储介质是磁盘,磁头在盘片上移动进行磁道寻址,行为类似播放一张唱片。这种结构的特点是,顺序访问时吞吐量较高,但是如果一旦对盘片有随机访问,那么大量的时间都会浪费在磁头的移动上,这时候就会导致每次IO的响应时间变长,极大的降低IO的响应速度。磁头在盘片上寻道的操作,类似电梯调度,实际上在最开始的时期,Linux把这个算法命名为Linux电梯算法,即:如果在寻道的过程中,能把顺序路过的相关磁道的数据请求都“顺便”处理掉,那么就可以在比较小影响响应速度的前提下,提高整体IO的吞吐量。这就是我们为什么要设计IO调度算法的原因。目前在内核中默认开启了三种算法/模式:noop,cfq和deadline。严格算应该是两种:因为第一种叫做noop,就是空操作调度算法,也就是没有任何调度操作,并不对io请求进行排序,仅仅做适当的io合并的一个fifo队列。目前内核中默认的调度算法应该是cfq,叫做完全公平队列调度。这个调度算法人如其名,它试图给所有进程提供一个完全公平的IO操作环境。注:请大家一定记住这个词语,cfq,完全公平队列调度,不然下文就没法看了。cfq为每个进程创建一个同步IO调度队列,并默认以时间片和请求数限定的方式分配IO资源,以此保证每个进程的IO资源占用是公平的,cfq还实现了针对进程级别的优先级调度,这个我们后面会详细解释。查看和修改IO调度算法的方法是:cfq是通用服务器比较好的IO调度算法选择,对桌面用户也是比较好的选择。但是对于很多IO压力较大的场景就并不是很适应,尤其是IO压力集中在某些进程上的场景。因为这种场景我们需要更多的满足某个或者某几个进程的IO响应速度,而不是让所有的进程公平的使用IO,比如数据库应用。deadline调度(最终期限调度)就是更适合上述场景的解决方案。deadline实现了四个队列:其中两个分别处理正常read和write,按扇区号排序,进行正常io的合并处理以提高吞吐量。因为IO请求可能会集中在某些磁盘位置,这样会导致新来的请求一直被合并,可能会有其他磁盘位置的io请求被饿死。另外两个处理超时read和write的队列,按请求创建时间排序,如果有超时的请求出现,就放进这两个队列,调度算法保证超时(达到最终期限时间)的队列中的请求会优先被处理,防止请求被饿死。不久前,内核还是默认标配四种算法,还有一种叫做as的算法(Anticipatory scheduler),预测调度算法。一个高大上的名字,搞得我一度认为Linux内核都会算命了。结果发现,无非是在基于deadline算法做io调度的之前等一小会时间,如果这段时间内有可以合并的io请求到来,就可以合并处理,提高deadline调度的在顺序读写情况下的数据吞吐量。其实这根本不是啥预测,我觉得不如叫撞大运调度算法,当然这种策略在某些特定场景差效果不错。但是在大多数场景下,这个调度不仅没有提高吞吐量,还降低了响应速度,所以内核干脆把它从默认配置里删除了。毕竟Linux的宗旨是实用,而我们也就不再这个调度算法上多费口舌了。1、cfq:完全公平队列调度cfq是内核默认选择的IO调度队列,它在桌面应用场景以及大多数常见应用场景下都是很好的选择。如何实现一个所谓的完全公平队列(Completely Fair Queueing)?首先我们要理解所谓的公平是对谁的公平?从操作系统的角度来说,产生操作行为的主体都是进程,所以这里的公平是针对每个进程而言的,我们要试图让进程可以公平的占用IO资源。那么如何让进程公平的占用IO资源?我们需要先理解什么是IO资源。当我们衡量一个IO资源的时候,一般喜欢用的是两个单位,一个是数据读写的带宽,另一个是数据读写的IOPS。带宽就是以时间为单位的读写数据量,比如,100Mbyte/s。而IOPS是以时间为单位的读写次数。在不同的读写情境下,这两个单位的表现可能不一样,但是可以确定的是,两个单位的任何一个达到了性能上限,都会成为IO的瓶颈。从机械硬盘的结构考虑,如果读写是顺序读写,那么IO的表现是可以通过比较少的IOPS达到较大的带宽,因为可以合并很多IO,也可以通过预读等方式加速数据读取效率。当IO的表现是偏向于随机读写的时候,那么IOPS就会变得更大,IO的请求的合并可能性下降,当每次io请求数据越少的时候,带宽表现就会越低。从这里我们可以理解,针对进程的IO资源的主要表现形式有两个: 进程在单位时间内提交的IO请求个数和进程占用IO的带宽。其实无论哪个,都是跟进程分配的IO处理时间长度紧密相关的。有时业务可以在较少IOPS的情况下占用较大带宽,另外一些则可能在较大IOPS的情况下占用较少带宽,所以对进程占用IO的时间进行调度才是相对最公平的。即,我不管你是IOPS高还是带宽占用高,到了时间咱就换下一个进程处理,你爱咋样咋样。所以,cfq就是试图给所有进程分配等同的块设备使用的时间片,进程在时间片内,可以将产生的IO请求提交给块设备进行处理,时间片结束,进程的请求将排进它自己的队列,等待下次调度的时候进行处理。这就是cfq的基本原理。当然,现实生活中不可能有真正的“公平”,常见的应用场景下,我们很肯能需要人为的对进程的IO占用进行人为指定优先级,这就像对进程的CPU占用设置优先级的概念一样。所以,除了针对时间片进行公平队列调度外,cfq还提供了优先级支持。每个进程都可以设置一个IO优先级,cfq会根据这个优先级的设置情况作为调度时的重要参考因素。优先级首先分成三大类:RT、BE、IDLE,它们分别是实时(Real Time)、最佳效果(Best Try)和闲置(Idle)三个类别,对每个类别的IO,cfq都使用不同的策略进行处理。另外,RT和BE类别中,分别又再划分了8个子优先级实现更细节的QOS需求,而IDLE只有一个子优先级。另外,我们都知道内核默认对存储的读写都是经过缓存(buffer/cache)的,在这种情况下,cfq是无法区分当前处理的请求是来自哪一个进程的。只有在进程使用同步方式(sync read或者sync wirte)或者直接IO(Direct IO)方式进行读写的时候,cfq才能区分出IO请求来自哪个进程。所以,除了针对每个进程实现的IO队列以外,还实现了一个公共的队列用来处理异步请求。当前内核已经实现了针对IO资源的cgroup资源隔离,所以在以上体系的基础上,cfq也实现了针对cgroup的调度支持。总的来说,cfq用了一系列的数据结构实现了以上所有复杂功能的支持,大家可以通过源代码看到其相关实现,文件在源代码目录下的block/cfq-iosched.c。1.1 cfq设计原理在此,我们对整体数据结构做一个简要描述:首先,cfq通过一个叫做cfq_data的数据结构维护了整个调度器流程。在一个支持了cgroup功能的cfq中,全部进程被分成了若干个contral group进行管理。每个cgroup在cfq中都有一个cfq_group的结构进行描述,所有的cgroup都被作为一个调度对象放进一个红黑树中,并以vdisktime为key进行排序。vdisktime这个时间纪录的是当前cgroup所占用的io时间,每次对cgroup进行调度时,总是通过红黑树选择当前vdisktime时间最少的cgroup进行处理,以保证所有cgroups之间的IO资源占用“公平”。当然我们知道,cgroup是可以对blkio进行资源比例分配的,其作用原理就是,分配比例大的cgroup占用vdisktime时间增长较慢,分配比例小的vdisktime时间增长较快,快慢与分配比例成正比。这样就做到了不同的cgroup分配的IO比例不一样,并且在cfq的角度看来依然是“公平“的。选择好了需要处理的cgroup(cfq_group)之后,调度器需要决策选择下一步的service_tree。service_tree这个数据结构对应的都是一系列的红黑树,主要目的是用来实现请求优先级分类的,就是RT、BE、IDLE的分类。每一个cfq_group都维护了7个service_trees,其定义如下:其中service_tree_idle就是用来给IDLE类型的请求进行排队用的红黑树。而上面二维数组,首先第一个维度针对RT和BE分别各实现了一个数组,每一个数组中都维护了三个红黑树,分别对应三种不同子类型的请求,分别是:SYNC、SYNC_NOIDLE以及ASYNC。我们可以认为SYNC相当于SYNC_IDLE并与SYNC_NOIDLE对应。idling是cfq在设计上为了尽量合并连续的IO请求以达到提高吞吐量的目的而加入的机制,我们可以理解为是一种“空转”等待机制。空转是指,当一个队列处理一个请求结束后,会在发生调度之前空等一小会时间,如果下一个请求到来,则可以减少磁头寻址,继续处理顺序的IO请求。为了实现这个功能,cfq在service_tree这层数据结构这实现了SYNC队列,如果请求是同步顺序请求,就入队这个service tree,如果请求是同步随机请求,则入队SYNC_NOIDLE队列,以判断下一个请求是否是顺序请求。所有的异步写操作请求将入队ASYNC的service tree,并且针对这个队列没有空转等待机制。此外,cfq还对SSD这样的硬盘有特殊调整,当cfq发现存储设备是一个ssd硬盘这样的队列深度更大的设备时,所有针对单独队列的空转都将不生效,所有的IO请求都将入队SYNC_NOIDLE这个service tree。每一个service tree都对应了若干个cfq_queue队列,每个cfq_queue队列对应一个进程,这个我们后续再详细说明。cfq_group还维护了一个在cgroup内部所有进程公用的异步IO请求队列,其结构如下:异步请求也分成了RT、BE、IDLE这三类进行处理,每一类对应一个cfq_queue进行排队。BE和RT也实现了优先级的支持,每一个类型有IOPRIO_BE_NR这么多个优先级,这个值定义为8,数组下标为0-7。我们目前分析的内核代码版本为Linux 4.4,可以看出,从cfq的角度来说,已经可以实现异步IO的cgroup支持了,我们需要定义一下这里所谓异步IO的含义,它仅仅表示从内存的buffer/cache中的数据同步到硬盘的IO请求,而不是aio(man 7 aio)或者linux的native异步io以及libaio机制,实际上这些所谓的“异步”IO机制,在内核中都是同步实现的(本质上冯诺伊曼计算机没有真正的“异步”机制)。我们在上面已经说明过,由于进程正常情况下都是将数据先写入buffer/cache,所以这种异步IO都是统一由cfq_group中的async请求队列处理的。那么为什么在上面的service_tree中还要实现和一个ASYNC的类型呢?这当然是为了支持区分进程的异步IO并使之可以“完全公平”做准备喽。实际上在最新的cgroup v2的blkio体系中,内核已经支持了针对buffer IO的cgroup限速支持,而以上这些可能容易混淆的一堆类型,都是在新的体系下需要用到的类型标记。新体系的复杂度更高了,功能也更加强大,但是大家先不要着急,正式的cgroup v2体系,在Linux 4.5发布的时候会正式跟大家见面。我们继续选择service_tree的过程,三种优先级类型的service_tree的选择就是根据类型的优先级来做选择的,RT优先级最高,BE其次,IDLE最低。就是说,RT里有,就会一直处理RT,RT没了再处理BE。每个service_tree对应一个元素为cfq_queue排队的红黑树,而每个cfq_queue就是内核为进程(线程)创建的请求队列。每一个cfq_queue都会维护一个rb_key的变量,这个变量实际上就是这个队列的IO服务时间(service time)。这里还是通过红黑树找到service time时间最短的那个cfq_queue进行服务,以保证“完全公平”。选择好了cfq_queue之后,就要开始处理这个队列里的IO请求了。这里的调度方式基本跟deadline类似。cfq_queue会对进入队列的每一个请求进行两次入队,一个放进fifo中,另一个放进按访问扇区顺序作为key的红黑树中。默认从红黑树中取请求进行处理,当请求的延时时间达到deadline时,就从红黑树中取等待时间最长的进行处理,以保证请求不被饿死。这就是整个cfq的调度流程,当然其中还有很多细枝末节没有交代,比如合并处理以及顺序处理等等。1.2 cfq的参数调整理解整个调度流程有助于我们决策如何调整cfq的相关参数。所有cfq的可调参数都可以在/sys/class/block/sda/queue/iosched/目录下找到,当然,在你的系统上,请将sda替换为相应的磁盘名称。我们来看一下都有什么:这些参数部分是跟机械硬盘磁头寻道方式有关的,如果其说明你看不懂,请先补充相关知识:back_seek_max:磁头可以向后寻址的最大范围,默认值为16M。back_seek_penalty:向后寻址的惩罚系数。这个值是跟向前寻址进行比较的。以上两个是为了防止磁头寻道发生抖动而导致寻址过慢而设置的。基本思路是这样,一个io请求到来的时候,cfq会根据其寻址位置预估一下其磁头寻道成本。设置一个最大值back_seek_max,对于请求所访问的扇区号在磁头后方的请求,只要寻址范围没有超过这个值,cfq会像向前寻址的请求一样处理它。再设置一个评估成本的系数back_seek_penalty,相对于磁头向前寻址,向后寻址的距离为1/2(1/back_seek_penalty)时,cfq认为这两个请求寻址的代价是相同。这两个参数实际上是cfq判断请求合并处理的条件限制,凡事复合这个条件的请求,都会尽量在本次请求处理的时候一起合并处理。fifo_expire_async:设置异步请求的超时时间。同步请求和异步请求是区分不同队列处理的,cfq在调度的时候一般情况都会优先处理同步请求,之后再处理异步请求,除非异步请求符合上述合并处理的条件限制范围内。当本进程的队列被调度时,cfq会优先检查是否有异步请求超时,就是超过fifo_expire_async参数的限制。如果有,则优先发送一个超时的请求,其余请求仍然按照优先级以及扇区编号大小来处理。fifo_expire_sync:这个参数跟上面的类似,区别是用来设置同步请求的超时时间。slice_idle:参数设置了一个等待时间。这让cfq在切换cfq_queue或service tree的时候等待一段时间,目的是提高机械硬盘的吞吐量。一般情况下,来自同一个cfq_queue或者service tree的IO请求的寻址局部性更好,所以这样可以减少磁盘的寻址次数。这个值在机械硬盘上默认为非零。当然在固态硬盘或者硬RAID设备上设置这个值为非零会降低存储的效率,因为固态硬盘没有磁头寻址这个概念,所以在这样的设备上应该设置为0,关闭此功能。group_idle:这个参数也跟上一个参数类似,区别是当cfq要切换cfq_group的时候会等待一段时间。在cgroup的场景下,如果我们沿用slice_idle的方式,那么空转等待可能会在cgroup组内每个进程的cfq_queue切换时发生。这样会如果这个进程一直有请求要处理的话,那么直到这个cgroup的配额被耗尽,同组中的其它进程也可能无法被调度到。这样会导致同组中的其它进程饿死而产生IO性能瓶颈。在这种情况下,我们可以将slice_idle = 0而group_idle = 8。这样空转等待就是以cgroup为单位进行的,而不是以cfq_queue的进程为单位进行,以防止上述问题产生。low_latency:这个是用来开启或关闭cfq的低延时(low latency)模式的开关。当这个开关打开时,cfq将会根据target_latency的参数设置来对每一个进程的分片时间(slice time)进行重新计算。这将有利于对吞吐量的公平(默认是对时间片分配的公平)。关闭这个参数(设置为0)将忽略target_latency的值。这将使系统中的进程完全按照时间片方式进行IO资源分配。这个开关默认是打开的。我们已经知道cfq设计上有“空转”(idling)这个概念,目的是为了可以让连续的读写操作尽可能多的合并处理,减少磁头的寻址操作以便增大吞吐量。如果有进程总是很快的进行顺序读写,那么它将因为cfq的空转等待命中率很高而导致其它需要处理IO的进程响应速度下降,如果另一个需要调度的进程不会发出大量顺序IO行为的话,系统中不同进程IO吞吐量的表现就会很不均衡。就比如,系统内存的cache中有很多脏页要写回时,桌面又要打开一个浏览器进行操作,这时脏页写回的后台行为就很可能会大量命中空转时间,而导致浏览器的小量IO一直等待,让用户感觉浏览器运行响应速度变慢。这个low_latency主要是对这种情况进行优化的选项,当其打开时,系统会根据target_latency的配置对因为命中空转而大量占用IO吞吐量的进程进行限制,以达到不同进程IO占用的吞吐量的相对均衡。这个开关比较合适在类似桌面应用的场景下打开。target_latency:当low_latency的值为开启状态时,cfq将根据这个值重新计算每个进程分配的IO时间片长度。quantum:这个参数用来设置每次从cfq_queue中处理多少个IO请求。在一个队列处理事件周期中,超过这个数字的IO请求将不会被处理。这个参数只对同步的请求有效。slice_sync:当一个cfq_queue队列被调度处理时,它可以被分配的处理总时间是通过这个值来作为一个计算参数指定的。公式为:time_slice = slice_sync + (slice_sync/5 * (4 - prio))。这个参数对同步请求有效。slice_async:这个值跟上一个类似,区别是对异步请求有效。slice_async_rq:这个参数用来限制在一个slice的时间范围内,一个队列最多可以处理的异步请求个数。请求被处理的最大个数还跟相关进程被设置的io优先级有关。1.3 cfq的IOPS模式我们已经知道,默认情况下cfq是以时间片方式支持的带优先级的调度来保证IO资源占用的公平。高优先级的进程将得到更多的时间片长度,而低优先级的进程时间片相对较小。当我们的存储是一个高速并且支持NCQ(原生指令队列)的设备的时候,我们最好可以让其可以从多个cfq队列中处理多路的请求,以便提升NCQ的利用率。此时使用时间片的分配方式分配资源就显得不合时宜了,因为基于时间片的分配,同一时刻最多能处理的请求队列只有一个。这时,我们需要切换cfq的模式为IOPS模式。切换方式很简单,就是将slice_idle=0即可。内核会自动检测你的存储设备是否支持NCQ,如果支持的话cfq会自动切换为IOPS模式。另外,在默认的基于优先级的时间片方式下,我们可以使用ionice命令来调整进程的IO优先级。进程默认分配的IO优先级是根据进程的nice值计算而来的,计算方法可以在man ionice中看到,这里不再废话。2、deadline:最终期限调度deadline调度算法相对cfq要简单很多。其设计目标是:在保证请求按照设备扇区的顺序进行访问的同时,兼顾其它请求不被饿死,要在一个最终期限前被调度到。我们知道磁头对磁盘的寻道是可以进行顺序访问和随机访问的,因为寻道延时时间的关系,顺序访问时IO的吞吐量更大,随机访问的吞吐量小。如果我们想为一个机械硬盘进行吞吐量优化的话,那么就可以让调度器按照尽量复合顺序访问的IO请求进行排序,之后请求以这样的顺序发送给硬盘,就可以使IO的吞吐量更大。但是这样做也有另一个问题,就是如果此时出现了一个请求,它要访问的磁道离目前磁头所在磁道很远,应用的请求又大量集中在目前磁道附近。导致大量请求一直会被合并和插队处理,而那个要访问比较远磁道的请求将因为一直不能被调度而饿死。deadline就是这样一种调度器,能在保证IO最大吞吐量的情况下,尽量使远端请求在一个期限内被调度而不被饿死的调度器。

如何提高Linux下块设备IO的整体性能

前言:本文主要讲解Linux IO调度层的三种模式:cfp、deadline和noop,并给出各自的优化和适用场景建议。IO调度发生在Linux内核的IO调度层。这个层次是针对Linux的整体IO层次体系来说的。从read()或者write()系统调用的角度来说,Linux整体IO体系可以分为七层,它们分别是:VFS层: 虚拟文件系统层。由于内核要跟多种文件系统打交道,而每一种文件系统所实现的数据结构和相关方法都可能不尽相同,所以,内核抽象了这一层,专门用来适配各种文件系统,并对外提供统一操作接口。文件系统层: 不同的文件系统实现自己的操作过程,提供自己特有的特征,具体不多说了,大家愿意的话自己去看代码即可。页缓存层: 负责真对page的缓存。通用块层: 由于绝大多数情况的io操作是跟块设备打交道,所以Linux在此提供了一个类似vfs层的块设备操作抽象层。下层对接各种不同属性的块设备,对上提供统一的Block IO请求标准。IO调度层 :因为绝大多数的块设备都是类似磁盘这样的设备,所以有必要根据这类设备的特点以及应用的不同特点来设置一些不同的调度算法和队列。以便在不同的应用环境下有针对性的提高磁盘的读写效率,这里就是大名鼎鼎的Linux电梯所起作用的地方。针对机械硬盘的各种调度方法就是在这实现的。块设备驱动层: 驱动层对外提供相对比较高级的设备操作接口,往往是C语言的,而下层对接设备本身的操作方法和规范。块设备层: 这层就是具体的物理设备了,定义了各种真对设备操作方法和规范。有一个已经整理好的[Linux IO结构图],非常经典,一图胜千言:我们今天要研究的内容主要在IO调度这一层。它要解决的核心问题是,如何提高块设备IO的整体性能?这一层也主要是针对机械硬盘结构而设计的。众所周知,机械硬盘的存储介质是磁盘,磁头在盘片上移动进行磁道寻址,行为类似播放一张唱片。这种结构的特点是,顺序访问时吞吐量较高,但是如果一旦对盘片有随机访问,那么大量的时间都会浪费在磁头的移动上,这时候就会导致每次IO的响应时间变长,极大的降低IO的响应速度。磁头在盘片上寻道的操作,类似电梯调度,实际上在最开始的时期,Linux把这个算法命名为Linux电梯算法,即:如果在寻道的过程中,能把顺序路过的相关磁道的数据请求都“顺便”处理掉,那么就可以在比较小影响响应速度的前提下,提高整体IO的吞吐量。这就是我们为什么要设计IO调度算法的原因。目前在内核中默认开启了三种算法/模式:noop,cfq和deadline。严格算应该是两种:因为第一种叫做noop,就是空操作调度算法,也就是没有任何调度操作,并不对io请求进行排序,仅仅做适当的io合并的一个fifo队列。目前内核中默认的调度算法应该是cfq,叫做完全公平队列调度。这个调度算法人如其名,它试图给所有进程提供一个完全公平的IO操作环境。注:请大家一定记住这个词语,cfq,完全公平队列调度,不然下文就没法看了。cfq为每个进程创建一个同步IO调度队列,并默认以时间片和请求数限定的方式分配IO资源,以此保证每个进程的IO资源占用是公平的,cfq还实现了针对进程级别的优先级调度,这个我们后面会详细解释。查看和修改IO调度算法的方法是:cfq是通用服务器比较好的IO调度算法选择,对桌面用户也是比较好的选择。但是对于很多IO压力较大的场景就并不是很适应,尤其是IO压力集中在某些进程上的场景。因为这种场景我们需要更多的满足某个或者某几个进程的IO响应速度,而不是让所有的进程公平的使用IO,比如数据库应用。deadline调度(最终期限调度)就是更适合上述场景的解决方案。deadline实现了四个队列:其中两个分别处理正常read和write,按扇区号排序,进行正常io的合并处理以提高吞吐量。因为IO请求可能会集中在某些磁盘位置,这样会导致新来的请求一直被合并,可能会有其他磁盘位置的io请求被饿死。另外两个处理超时read和write的队列,按请求创建时间排序,如果有超时的请求出现,就放进这两个队列,调度算法保证超时(达到最终期限时间)的队列中的请求会优先被处理,防止请求被饿死。不久前,内核还是默认标配四种算法,还有一种叫做as的算法(Anticipatory scheduler),预测调度算法。一个高大上的名字,搞得我一度认为Linux内核都会算命了。结果发现,无非是在基于deadline算法做io调度的之前等一小会时间,如果这段时间内有可以合并的io请求到来,就可以合并处理,提高deadline调度的在顺序读写情况下的数据吞吐量。其实这根本不是啥预测,我觉得不如叫撞大运调度算法,当然这种策略在某些特定场景差效果不错。但是在大多数场景下,这个调度不仅没有提高吞吐量,还降低了响应速度,所以内核干脆把它从默认配置里删除了。毕竟Linux的宗旨是实用,而我们也就不再这个调度算法上多费口舌了。1、cfq:完全公平队列调度cfq是内核默认选择的IO调度队列,它在桌面应用场景以及大多数常见应用场景下都是很好的选择。如何实现一个所谓的完全公平队列(Completely Fair Queueing)?首先我们要理解所谓的公平是对谁的公平?从操作系统的角度来说,产生操作行为的主体都是进程,所以这里的公平是针对每个进程而言的,我们要试图让进程可以公平的占用IO资源。那么如何让进程公平的占用IO资源?我们需要先理解什么是IO资源。当我们衡量一个IO资源的时候,一般喜欢用的是两个单位,一个是数据读写的带宽,另一个是数据读写的IOPS。带宽就是以时间为单位的读写数据量,比如,100Mbyte/s。而IOPS是以时间为单位的读写次数。在不同的读写情境下,这两个单位的表现可能不一样,但是可以确定的是,两个单位的任何一个达到了性能上限,都会成为IO的瓶颈。从机械硬盘的结构考虑,如果读写是顺序读写,那么IO的表现是可以通过比较少的IOPS达到较大的带宽,因为可以合并很多IO,也可以通过预读等方式加速数据读取效率。当IO的表现是偏向于随机读写的时候,那么IOPS就会变得更大,IO的请求的合并可能性下降,当每次io请求数据越少的时候,带宽表现就会越低。从这里我们可以理解,针对进程的IO资源的主要表现形式有两个: 进程在单位时间内提交的IO请求个数和进程占用IO的带宽。其实无论哪个,都是跟进程分配的IO处理时间长度紧密相关的。有时业务可以在较少IOPS的情况下占用较大带宽,另外一些则可能在较大IOPS的情况下占用较少带宽,所以对进程占用IO的时间进行调度才是相对最公平的。即,我不管你是IOPS高还是带宽占用高,到了时间咱就换下一个进程处理,你爱咋样咋样。所以,cfq就是试图给所有进程分配等同的块设备使用的时间片,进程在时间片内,可以将产生的IO请求提交给块设备进行处理,时间片结束,进程的请求将排进它自己的队列,等待下次调度的时候进行处理。这就是cfq的基本原理。当然,现实生活中不可能有真正的“公平”,常见的应用场景下,我们很肯能需要人为的对进程的IO占用进行人为指定优先级,这就像对进程的CPU占用设置优先级的概念一样。所以,除了针对时间片进行公平队列调度外,cfq还提供了优先级支持。每个进程都可以设置一个IO优先级,cfq会根据这个优先级的设置情况作为调度时的重要参考因素。优先级首先分成三大类:RT、BE、IDLE,它们分别是实时(Real Time)、最佳效果(Best Try)和闲置(Idle)三个类别,对每个类别的IO,cfq都使用不同的策略进行处理。另外,RT和BE类别中,分别又再划分了8个子优先级实现更细节的QOS需求,而IDLE只有一个子优先级。另外,我们都知道内核默认对存储的读写都是经过缓存(buffer/cache)的,在这种情况下,cfq是无法区分当前处理的请求是来自哪一个进程的。只有在进程使用同步方式(sync read或者sync wirte)或者直接IO(Direct IO)方式进行读写的时候,cfq才能区分出IO请求来自哪个进程。所以,除了针对每个进程实现的IO队列以外,还实现了一个公共的队列用来处理异步请求。当前内核已经实现了针对IO资源的cgroup资源隔离,所以在以上体系的基础上,cfq也实现了针对cgroup的调度支持。总的来说,cfq用了一系列的数据结构实现了以上所有复杂功能的支持,大家可以通过源代码看到其相关实现,文件在源代码目录下的block/cfq-iosched.c。1.1 cfq设计原理在此,我们对整体数据结构做一个简要描述:首先,cfq通过一个叫做cfq_data的数据结构维护了整个调度器流程。在一个支持了cgroup功能的cfq中,全部进程被分成了若干个contral group进行管理。每个cgroup在cfq中都有一个cfq_group的结构进行描述,所有的cgroup都被作为一个调度对象放进一个红黑树中,并以vdisktime为key进行排序。vdisktime这个时间纪录的是当前cgroup所占用的io时间,每次对cgroup进行调度时,总是通过红黑树选择当前vdisktime时间最少的cgroup进行处理,以保证所有cgroups之间的IO资源占用“公平”。当然我们知道,cgroup是可以对blkio进行资源比例分配的,其作用原理就是,分配比例大的cgroup占用vdisktime时间增长较慢,分配比例小的vdisktime时间增长较快,快慢与分配比例成正比。这样就做到了不同的cgroup分配的IO比例不一样,并且在cfq的角度看来依然是“公平“的。选择好了需要处理的cgroup(cfq_group)之后,调度器需要决策选择下一步的service_tree。service_tree这个数据结构对应的都是一系列的红黑树,主要目的是用来实现请求优先级分类的,就是RT、BE、IDLE的分类。每一个cfq_group都维护了7个service_trees,其定义如下:其中service_tree_idle就是用来给IDLE类型的请求进行排队用的红黑树。而上面二维数组,首先第一个维度针对RT和BE分别各实现了一个数组,每一个数组中都维护了三个红黑树,分别对应三种不同子类型的请求,分别是:SYNC、SYNC_NOIDLE以及ASYNC。我们可以认为SYNC相当于SYNC_IDLE并与SYNC_NOIDLE对应。idling是cfq在设计上为了尽量合并连续的IO请求以达到提高吞吐量的目的而加入的机制,我们可以理解为是一种“空转”等待机制。空转是指,当一个队列处理一个请求结束后,会在发生调度之前空等一小会时间,如果下一个请求到来,则可以减少磁头寻址,继续处理顺序的IO请求。为了实现这个功能,cfq在service_tree这层数据结构这实现了SYNC队列,如果请求是同步顺序请求,就入队这个service tree,如果请求是同步随机请求,则入队SYNC_NOIDLE队列,以判断下一个请求是否是顺序请求。所有的异步写操作请求将入队ASYNC的service tree,并且针对这个队列没有空转等待机制。此外,cfq还对SSD这样的硬盘有特殊调整,当cfq发现存储设备是一个ssd硬盘这样的队列深度更大的设备时,所有针对单独队列的空转都将不生效,所有的IO请求都将入队SYNC_NOIDLE这个service tree。每一个service tree都对应了若干个cfq_queue队列,每个cfq_queue队列对应一个进程,这个我们后续再详细说明。cfq_group还维护了一个在cgroup内部所有进程公用的异步IO请求队列,其结构如下:异步请求也分成了RT、BE、IDLE这三类进行处理,每一类对应一个cfq_queue进行排队。BE和RT也实现了优先级的支持,每一个类型有IOPRIO_BE_NR这么多个优先级,这个值定义为8,数组下标为0-7。我们目前分析的内核代码版本为Linux 4.4,可以看出,从cfq的角度来说,已经可以实现异步IO的cgroup支持了,我们需要定义一下这里所谓异步IO的含义,它仅仅表示从内存的buffer/cache中的数据同步到硬盘的IO请求,而不是aio(man 7 aio)或者linux的native异步io以及libaio机制,实际上这些所谓的“异步”IO机制,在内核中都是同步实现的(本质上冯诺伊曼计算机没有真正的“异步”机制)。我们在上面已经说明过,由于进程正常情况下都是将数据先写入buffer/cache,所以这种异步IO都是统一由cfq_group中的async请求队列处理的。那么为什么在上面的service_tree中还要实现和一个ASYNC的类型呢?这当然是为了支持区分进程的异步IO并使之可以“完全公平”做准备喽。实际上在最新的cgroup v2的blkio体系中,内核已经支持了针对buffer IO的cgroup限速支持,而以上这些可能容易混淆的一堆类型,都是在新的体系下需要用到的类型标记。新体系的复杂度更高了,功能也更加强大,但是大家先不要着急,正式的cgroup v2体系,在Linux 4.5发布的时候会正式跟大家见面。我们继续选择service_tree的过程,三种优先级类型的service_tree的选择就是根据类型的优先级来做选择的,RT优先级最高,BE其次,IDLE最低。就是说,RT里有,就会一直处理RT,RT没了再处理BE。每个service_tree对应一个元素为cfq_queue排队的红黑树,而每个cfq_queue就是内核为进程(线程)创建的请求队列。每一个cfq_queue都会维护一个rb_key的变量,这个变量实际上就是这个队列的IO服务时间(service time)。这里还是通过红黑树找到service time时间最短的那个cfq_queue进行服务,以保证“完全公平”。选择好了cfq_queue之后,就要开始处理这个队列里的IO请求了。这里的调度方式基本跟deadline类似。cfq_queue会对进入队列的每一个请求进行两次入队,一个放进fifo中,另一个放进按访问扇区顺序作为key的红黑树中。默认从红黑树中取请求进行处理,当请求的延时时间达到deadline时,就从红黑树中取等待时间最长的进行处理,以保证请求不被饿死。这就是整个cfq的调度流程,当然其中还有很多细枝末节没有交代,比如合并处理以及顺序处理等等。1.2 cfq的参数调整理解整个调度流程有助于我们决策如何调整cfq的相关参数。所有cfq的可调参数都可以在/sys/class/block/sda/queue/iosched/目录下找到,当然,在你的系统上,请将sda替换为相应的磁盘名称。我们来看一下都有什么:这些参数部分是跟机械硬盘磁头寻道方式有关的,如果其说明你看不懂,请先补充相关知识:back_seek_max:磁头可以向后寻址的最大范围,默认值为16M。back_seek_penalty:向后寻址的惩罚系数。这个值是跟向前寻址进行比较的。以上两个是为了防止磁头寻道发生抖动而导致寻址过慢而设置的。基本思路是这样,一个io请求到来的时候,cfq会根据其寻址位置预估一下其磁头寻道成本。设置一个最大值back_seek_max,对于请求所访问的扇区号在磁头后方的请求,只要寻址范围没有超过这个值,cfq会像向前寻址的请求一样处理它。再设置一个评估成本的系数back_seek_penalty,相对于磁头向前寻址,向后寻址的距离为1/2(1/back_seek_penalty)时,cfq认为这两个请求寻址的代价是相同。这两个参数实际上是cfq判断请求合并处理的条件限制,凡事复合这个条件的请求,都会尽量在本次请求处理的时候一起合并处理。fifo_expire_async:设置异步请求的超时时间。同步请求和异步请求是区分不同队列处理的,cfq在调度的时候一般情况都会优先处理同步请求,之后再处理异步请求,除非异步请求符合上述合并处理的条件限制范围内。当本进程的队列被调度时,cfq会优先检查是否有异步请求超时,就是超过fifo_expire_async参数的限制。如果有,则优先发送一个超时的请求,其余请求仍然按照优先级以及扇区编号大小来处理。fifo_expire_sync:这个参数跟上面的类似,区别是用来设置同步请求的超时时间。slice_idle:参数设置了一个等待时间。这让cfq在切换cfq_queue或service tree的时候等待一段时间,目的是提高机械硬盘的吞吐量。一般情况下,来自同一个cfq_queue或者service tree的IO请求的寻址局部性更好,所以这样可以减少磁盘的寻址次数。这个值在机械硬盘上默认为非零。当然在固态硬盘或者硬RAID设备上设置这个值为非零会降低存储的效率,因为固态硬盘没有磁头寻址这个概念,所以在这样的设备上应该设置为0,关闭此功能。group_idle:这个参数也跟上一个参数类似,区别是当cfq要切换cfq_group的时候会等待一段时间。在cgroup的场景下,如果我们沿用slice_idle的方式,那么空转等待可能会在cgroup组内每个进程的cfq_queue切换时发生。这样会如果这个进程一直有请求要处理的话,那么直到这个cgroup的配额被耗尽,同组中的其它进程也可能无法被调度到。这样会导致同组中的其它进程饿死而产生IO性能瓶颈。在这种情况下,我们可以将slice_idle = 0而group_idle = 8。这样空转等待就是以cgroup为单位进行的,而不是以cfq_queue的进程为单位进行,以防止上述问题产生。low_latency:这个是用来开启或关闭cfq的低延时(low latency)模式的开关。当这个开关打开时,cfq将会根据target_latency的参数设置来对每一个进程的分片时间(slice time)进行重新计算。这将有利于对吞吐量的公平(默认是对时间片分配的公平)。关闭这个参数(设置为0)将忽略target_latency的值。这将使系统中的进程完全按照时间片方式进行IO资源分配。这个开关默认是打开的。我们已经知道cfq设计上有“空转”(idling)这个概念,目的是为了可以让连续的读写操作尽可能多的合并处理,减少磁头的寻址操作以便增大吞吐量。如果有进程总是很快的进行顺序读写,那么它将因为cfq的空转等待命中率很高而导致其它需要处理IO的进程响应速度下降,如果另一个需要调度的进程不会发出大量顺序IO行为的话,系统中不同进程IO吞吐量的表现就会很不均衡。就比如,系统内存的cache中有很多脏页要写回时,桌面又要打开一个浏览器进行操作,这时脏页写回的后台行为就很可能会大量命中空转时间,而导致浏览器的小量IO一直等待,让用户感觉浏览器运行响应速度变慢。这个low_latency主要是对这种情况进行优化的选项,当其打开时,系统会根据target_latency的配置对因为命中空转而大量占用IO吞吐量的进程进行限制,以达到不同进程IO占用的吞吐量的相对均衡。这个开关比较合适在类似桌面应用的场景下打开。target_latency:当low_latency的值为开启状态时,cfq将根据这个值重新计算每个进程分配的IO时间片长度。quantum:这个参数用来设置每次从cfq_queue中处理多少个IO请求。在一个队列处理事件周期中,超过这个数字的IO请求将不会被处理。这个参数只对同步的请求有效。slice_sync:当一个cfq_queue队列被调度处理时,它可以被分配的处理总时间是通过这个值来作为一个计算参数指定的。公式为:time_slice = slice_sync + (slice_sync/5 * (4 - prio))。这个参数对同步请求有效。slice_async:这个值跟上一个类似,区别是对异步请求有效。slice_async_rq:这个参数用来限制在一个slice的时间范围内,一个队列最多可以处理的异步请求个数。请求被处理的最大个数还跟相关进程被设置的io优先级有关。1.3 cfq的IOPS模式我们已经知道,默认情况下cfq是以时间片方式支持的带优先级的调度来保证IO资源占用的公平。高优先级的进程将得到更多的时间片长度,而低优先级的进程时间片相对较小。当我们的存储是一个高速并且支持NCQ(原生指令队列)的设备的时候,我们最好可以让其可以从多个cfq队列中处理多路的请求,以便提升NCQ的利用率。此时使用时间片的分配方式分配资源就显得不合时宜了,因为基于时间片的分配,同一时刻最多能处理的请求队列只有一个。这时,我们需要切换cfq的模式为IOPS模式。切换方式很简单,就是将slice_idle=0即可。内核会自动检测你的存储设备是否支持NCQ,如果支持的话cfq会自动切换为IOPS模式。另外,在默认的基于优先级的时间片方式下,我们可以使用ionice命令来调整进程的IO优先级。进程默认分配的IO优先级是根据进程的nice值计算而来的,计算方法可以在man ionice中看到,这里不再废话。2、deadline:最终期限调度deadline调度算法相对cfq要简单很多。其设计目标是:在保证请求按照设备扇区的顺序进行访问的同时,兼顾其它请求不被饿死,要在一个最终期限前被调度到。我们知道磁头对磁盘的寻道是可以进行顺序访问和随机访问的,因为寻道延时时间的关系,顺序访问时IO的吞吐量更大,随机访问的吞吐量小。如果我们想为一个机械硬盘进行吞吐量优化的话,那么就可以让调度器按照尽量复合顺序访问的IO请求进行排序,之后请求以这样的顺序发送给硬盘,就可以使IO的吞吐量更大。但是这样做也有另一个问题,就是如果此时出现了一个请求,它要访问的磁道离目前磁头所在磁道很远,应用的请求又大量集中在目前磁道附近。导致大量请求一直会被合并和插队处理,而那个要访问比较远磁道的请求将因为一直不能被调度而饿死。deadline就是这样一种调度器,能在保证IO最大吞吐量的情况下,尽量使远端请求在一个期限内被调度而不被饿死的调度器。

如何提高Linux下块设备IO的整体性能

前言:本文主要讲解Linux IO调度层的三种模式:cfp、deadline和noop,并给出各自的优化和适用场景建议。IO调度发生在Linux内核的IO调度层。这个层次是针对Linux的整体IO层次体系来说的。从read()或者write()系统调用的角度来说,Linux整体IO体系可以分为七层,它们分别是:VFS层: 虚拟文件系统层。由于内核要跟多种文件系统打交道,而每一种文件系统所实现的数据结构和相关方法都可能不尽相同,所以,内核抽象了这一层,专门用来适配各种文件系统,并对外提供统一操作接口。文件系统层: 不同的文件系统实现自己的操作过程,提供自己特有的特征,具体不多说了,大家愿意的话自己去看代码即可。页缓存层: 负责真对page的缓存。通用块层: 由于绝大多数情况的io操作是跟块设备打交道,所以Linux在此提供了一个类似vfs层的块设备操作抽象层。下层对接各种不同属性的块设备,对上提供统一的Block IO请求标准。IO调度层 :因为绝大多数的块设备都是类似磁盘这样的设备,所以有必要根据这类设备的特点以及应用的不同特点来设置一些不同的调度算法和队列。以便在不同的应用环境下有针对性的提高磁盘的读写效率,这里就是大名鼎鼎的Linux电梯所起作用的地方。针对机械硬盘的各种调度方法就是在这实现的。块设备驱动层: 驱动层对外提供相对比较高级的设备操作接口,往往是C语言的,而下层对接设备本身的操作方法和规范。块设备层: 这层就是具体的物理设备了,定义了各种真对设备操作方法和规范。有一个已经整理好的[Linux IO结构图],非常经典,一图胜千言:我们今天要研究的内容主要在IO调度这一层。它要解决的核心问题是,如何提高块设备IO的整体性能?这一层也主要是针对机械硬盘结构而设计的。众所周知,机械硬盘的存储介质是磁盘,磁头在盘片上移动进行磁道寻址,行为类似播放一张唱片。这种结构的特点是,顺序访问时吞吐量较高,但是如果一旦对盘片有随机访问,那么大量的时间都会浪费在磁头的移动上,这时候就会导致每次IO的响应时间变长,极大的降低IO的响应速度。磁头在盘片上寻道的操作,类似电梯调度,实际上在最开始的时期,Linux把这个算法命名为Linux电梯算法,即:如果在寻道的过程中,能把顺序路过的相关磁道的数据请求都“顺便”处理掉,那么就可以在比较小影响响应速度的前提下,提高整体IO的吞吐量。这就是我们为什么要设计IO调度算法的原因。目前在内核中默认开启了三种算法/模式:noop,cfq和deadline。严格算应该是两种:因为第一种叫做noop,就是空操作调度算法,也就是没有任何调度操作,并不对io请求进行排序,仅仅做适当的io合并的一个fifo队列。目前内核中默认的调度算法应该是cfq,叫做完全公平队列调度。这个调度算法人如其名,它试图给所有进程提供一个完全公平的IO操作环境。注:请大家一定记住这个词语,cfq,完全公平队列调度,不然下文就没法看了。cfq为每个进程创建一个同步IO调度队列,并默认以时间片和请求数限定的方式分配IO资源,以此保证每个进程的IO资源占用是公平的,cfq还实现了针对进程级别的优先级调度,这个我们后面会详细解释。查看和修改IO调度算法的方法是:cfq是通用服务器比较好的IO调度算法选择,对桌面用户也是比较好的选择。但是对于很多IO压力较大的场景就并不是很适应,尤其是IO压力集中在某些进程上的场景。因为这种场景我们需要更多的满足某个或者某几个进程的IO响应速度,而不是让所有的进程公平的使用IO,比如数据库应用。deadline调度(最终期限调度)就是更适合上述场景的解决方案。deadline实现了四个队列:其中两个分别处理正常read和write,按扇区号排序,进行正常io的合并处理以提高吞吐量。因为IO请求可能会集中在某些磁盘位置,这样会导致新来的请求一直被合并,可能会有其他磁盘位置的io请求被饿死。另外两个处理超时read和write的队列,按请求创建时间排序,如果有超时的请求出现,就放进这两个队列,调度算法保证超时(达到最终期限时间)的队列中的请求会优先被处理,防止请求被饿死。不久前,内核还是默认标配四种算法,还有一种叫做as的算法(Anticipatory scheduler),预测调度算法。一个高大上的名字,搞得我一度认为Linux内核都会算命了。结果发现,无非是在基于deadline算法做io调度的之前等一小会时间,如果这段时间内有可以合并的io请求到来,就可以合并处理,提高deadline调度的在顺序读写情况下的数据吞吐量。其实这根本不是啥预测,我觉得不如叫撞大运调度算法,当然这种策略在某些特定场景差效果不错。但是在大多数场景下,这个调度不仅没有提高吞吐量,还降低了响应速度,所以内核干脆把它从默认配置里删除了。毕竟Linux的宗旨是实用,而我们也就不再这个调度算法上多费口舌了。1、cfq:完全公平队列调度cfq是内核默认选择的IO调度队列,它在桌面应用场景以及大多数常见应用场景下都是很好的选择。如何实现一个所谓的完全公平队列(Completely Fair Queueing)?首先我们要理解所谓的公平是对谁的公平?从操作系统的角度来说,产生操作行为的主体都是进程,所以这里的公平是针对每个进程而言的,我们要试图让进程可以公平的占用IO资源。那么如何让进程公平的占用IO资源?我们需要先理解什么是IO资源。当我们衡量一个IO资源的时候,一般喜欢用的是两个单位,一个是数据读写的带宽,另一个是数据读写的IOPS。带宽就是以时间为单位的读写数据量,比如,100Mbyte/s。而IOPS是以时间为单位的读写次数。在不同的读写情境下,这两个单位的表现可能不一样,但是可以确定的是,两个单位的任何一个达到了性能上限,都会成为IO的瓶颈。从机械硬盘的结构考虑,如果读写是顺序读写,那么IO的表现是可以通过比较少的IOPS达到较大的带宽,因为可以合并很多IO,也可以通过预读等方式加速数据读取效率。当IO的表现是偏向于随机读写的时候,那么IOPS就会变得更大,IO的请求的合并可能性下降,当每次io请求数据越少的时候,带宽表现就会越低。从这里我们可以理解,针对进程的IO资源的主要表现形式有两个: 进程在单位时间内提交的IO请求个数和进程占用IO的带宽。其实无论哪个,都是跟进程分配的IO处理时间长度紧密相关的。有时业务可以在较少IOPS的情况下占用较大带宽,另外一些则可能在较大IOPS的情况下占用较少带宽,所以对进程占用IO的时间进行调度才是相对最公平的。即,我不管你是IOPS高还是带宽占用高,到了时间咱就换下一个进程处理,你爱咋样咋样。所以,cfq就是试图给所有进程分配等同的块设备使用的时间片,进程在时间片内,可以将产生的IO请求提交给块设备进行处理,时间片结束,进程的请求将排进它自己的队列,等待下次调度的时候进行处理。这就是cfq的基本原理。当然,现实生活中不可能有真正的“公平”,常见的应用场景下,我们很肯能需要人为的对进程的IO占用进行人为指定优先级,这就像对进程的CPU占用设置优先级的概念一样。所以,除了针对时间片进行公平队列调度外,cfq还提供了优先级支持。每个进程都可以设置一个IO优先级,cfq会根据这个优先级的设置情况作为调度时的重要参考因素。优先级首先分成三大类:RT、BE、IDLE,它们分别是实时(Real Time)、最佳效果(Best Try)和闲置(Idle)三个类别,对每个类别的IO,cfq都使用不同的策略进行处理。另外,RT和BE类别中,分别又再划分了8个子优先级实现更细节的QOS需求,而IDLE只有一个子优先级。另外,我们都知道内核默认对存储的读写都是经过缓存(buffer/cache)的,在这种情况下,cfq是无法区分当前处理的请求是来自哪一个进程的。只有在进程使用同步方式(sync read或者sync wirte)或者直接IO(Direct IO)方式进行读写的时候,cfq才能区分出IO请求来自哪个进程。所以,除了针对每个进程实现的IO队列以外,还实现了一个公共的队列用来处理异步请求。当前内核已经实现了针对IO资源的cgroup资源隔离,所以在以上体系的基础上,cfq也实现了针对cgroup的调度支持。总的来说,cfq用了一系列的数据结构实现了以上所有复杂功能的支持,大家可以通过源代码看到其相关实现,文件在源代码目录下的block/cfq-iosched.c。1.1 cfq设计原理在此,我们对整体数据结构做一个简要描述:首先,cfq通过一个叫做cfq_data的数据结构维护了整个调度器流程。在一个支持了cgroup功能的cfq中,全部进程被分成了若干个contral group进行管理。每个cgroup在cfq中都有一个cfq_group的结构进行描述,所有的cgroup都被作为一个调度对象放进一个红黑树中,并以vdisktime为key进行排序。vdisktime这个时间纪录的是当前cgroup所占用的io时间,每次对cgroup进行调度时,总是通过红黑树选择当前vdisktime时间最少的cgroup进行处理,以保证所有cgroups之间的IO资源占用“公平”。当然我们知道,cgroup是可以对blkio进行资源比例分配的,其作用原理就是,分配比例大的cgroup占用vdisktime时间增长较慢,分配比例小的vdisktime时间增长较快,快慢与分配比例成正比。这样就做到了不同的cgroup分配的IO比例不一样,并且在cfq的角度看来依然是“公平“的。选择好了需要处理的cgroup(cfq_group)之后,调度器需要决策选择下一步的service_tree。service_tree这个数据结构对应的都是一系列的红黑树,主要目的是用来实现请求优先级分类的,就是RT、BE、IDLE的分类。每一个cfq_group都维护了7个service_trees,其定义如下:其中service_tree_idle就是用来给IDLE类型的请求进行排队用的红黑树。而上面二维数组,首先第一个维度针对RT和BE分别各实现了一个数组,每一个数组中都维护了三个红黑树,分别对应三种不同子类型的请求,分别是:SYNC、SYNC_NOIDLE以及ASYNC。我们可以认为SYNC相当于SYNC_IDLE并与SYNC_NOIDLE对应。idling是cfq在设计上为了尽量合并连续的IO请求以达到提高吞吐量的目的而加入的机制,我们可以理解为是一种“空转”等待机制。空转是指,当一个队列处理一个请求结束后,会在发生调度之前空等一小会时间,如果下一个请求到来,则可以减少磁头寻址,继续处理顺序的IO请求。为了实现这个功能,cfq在service_tree这层数据结构这实现了SYNC队列,如果请求是同步顺序请求,就入队这个service tree,如果请求是同步随机请求,则入队SYNC_NOIDLE队列,以判断下一个请求是否是顺序请求。所有的异步写操作请求将入队ASYNC的service tree,并且针对这个队列没有空转等待机制。此外,cfq还对SSD这样的硬盘有特殊调整,当cfq发现存储设备是一个ssd硬盘这样的队列深度更大的设备时,所有针对单独队列的空转都将不生效,所有的IO请求都将入队SYNC_NOIDLE这个service tree。每一个service tree都对应了若干个cfq_queue队列,每个cfq_queue队列对应一个进程,这个我们后续再详细说明。cfq_group还维护了一个在cgroup内部所有进程公用的异步IO请求队列,其结构如下:异步请求也分成了RT、BE、IDLE这三类进行处理,每一类对应一个cfq_queue进行排队。BE和RT也实现了优先级的支持,每一个类型有IOPRIO_BE_NR这么多个优先级,这个值定义为8,数组下标为0-7。我们目前分析的内核代码版本为Linux 4.4,可以看出,从cfq的角度来说,已经可以实现异步IO的cgroup支持了,我们需要定义一下这里所谓异步IO的含义,它仅仅表示从内存的buffer/cache中的数据同步到硬盘的IO请求,而不是aio(man 7 aio)或者linux的native异步io以及libaio机制,实际上这些所谓的“异步”IO机制,在内核中都是同步实现的(本质上冯诺伊曼计算机没有真正的“异步”机制)。我们在上面已经说明过,由于进程正常情况下都是将数据先写入buffer/cache,所以这种异步IO都是统一由cfq_group中的async请求队列处理的。那么为什么在上面的service_tree中还要实现和一个ASYNC的类型呢?这当然是为了支持区分进程的异步IO并使之可以“完全公平”做准备喽。实际上在最新的cgroup v2的blkio体系中,内核已经支持了针对buffer IO的cgroup限速支持,而以上这些可能容易混淆的一堆类型,都是在新的体系下需要用到的类型标记。新体系的复杂度更高了,功能也更加强大,但是大家先不要着急,正式的cgroup v2体系,在Linux 4.5发布的时候会正式跟大家见面。我们继续选择service_tree的过程,三种优先级类型的service_tree的选择就是根据类型的优先级来做选择的,RT优先级最高,BE其次,IDLE最低。就是说,RT里有,就会一直处理RT,RT没了再处理BE。每个service_tree对应一个元素为cfq_queue排队的红黑树,而每个cfq_queue就是内核为进程(线程)创建的请求队列。每一个cfq_queue都会维护一个rb_key的变量,这个变量实际上就是这个队列的IO服务时间(service time)。这里还是通过红黑树找到service time时间最短的那个cfq_queue进行服务,以保证“完全公平”。选择好了cfq_queue之后,就要开始处理这个队列里的IO请求了。这里的调度方式基本跟deadline类似。cfq_queue会对进入队列的每一个请求进行两次入队,一个放进fifo中,另一个放进按访问扇区顺序作为key的红黑树中。默认从红黑树中取请求进行处理,当请求的延时时间达到deadline时,就从红黑树中取等待时间最长的进行处理,以保证请求不被饿死。这就是整个cfq的调度流程,当然其中还有很多细枝末节没有交代,比如合并处理以及顺序处理等等。1.2 cfq的参数调整理解整个调度流程有助于我们决策如何调整cfq的相关参数。所有cfq的可调参数都可以在/sys/class/block/sda/queue/iosched/目录下找到,当然,在你的系统上,请将sda替换为相应的磁盘名称。我们来看一下都有什么:这些参数部分是跟机械硬盘磁头寻道方式有关的,如果其说明你看不懂,请先补充相关知识:back_seek_max:磁头可以向后寻址的最大范围,默认值为16M。back_seek_penalty:向后寻址的惩罚系数。这个值是跟向前寻址进行比较的。以上两个是为了防止磁头寻道发生抖动而导致寻址过慢而设置的。基本思路是这样,一个io请求到来的时候,cfq会根据其寻址位置预估一下其磁头寻道成本。设置一个最大值back_seek_max,对于请求所访问的扇区号在磁头后方的请求,只要寻址范围没有超过这个值,cfq会像向前寻址的请求一样处理它。再设置一个评估成本的系数back_seek_penalty,相对于磁头向前寻址,向后寻址的距离为1/2(1/back_seek_penalty)时,cfq认为这两个请求寻址的代价是相同。这两个参数实际上是cfq判断请求合并处理的条件限制,凡事复合这个条件的请求,都会尽量在本次请求处理的时候一起合并处理。fifo_expire_async:设置异步请求的超时时间。同步请求和异步请求是区分不同队列处理的,cfq在调度的时候一般情况都会优先处理同步请求,之后再处理异步请求,除非异步请求符合上述合并处理的条件限制范围内。当本进程的队列被调度时,cfq会优先检查是否有异步请求超时,就是超过fifo_expire_async参数的限制。如果有,则优先发送一个超时的请求,其余请求仍然按照优先级以及扇区编号大小来处理。fifo_expire_sync:这个参数跟上面的类似,区别是用来设置同步请求的超时时间。slice_idle:参数设置了一个等待时间。这让cfq在切换cfq_queue或service tree的时候等待一段时间,目的是提高机械硬盘的吞吐量。一般情况下,来自同一个cfq_queue或者service tree的IO请求的寻址局部性更好,所以这样可以减少磁盘的寻址次数。这个值在机械硬盘上默认为非零。当然在固态硬盘或者硬RAID设备上设置这个值为非零会降低存储的效率,因为固态硬盘没有磁头寻址这个概念,所以在这样的设备上应该设置为0,关闭此功能。group_idle:这个参数也跟上一个参数类似,区别是当cfq要切换cfq_group的时候会等待一段时间。在cgroup的场景下,如果我们沿用slice_idle的方式,那么空转等待可能会在cgroup组内每个进程的cfq_queue切换时发生。这样会如果这个进程一直有请求要处理的话,那么直到这个cgroup的配额被耗尽,同组中的其它进程也可能无法被调度到。这样会导致同组中的其它进程饿死而产生IO性能瓶颈。在这种情况下,我们可以将slice_idle = 0而group_idle = 8。这样空转等待就是以cgroup为单位进行的,而不是以cfq_queue的进程为单位进行,以防止上述问题产生。low_latency:这个是用来开启或关闭cfq的低延时(low latency)模式的开关。当这个开关打开时,cfq将会根据target_latency的参数设置来对每一个进程的分片时间(slice time)进行重新计算。这将有利于对吞吐量的公平(默认是对时间片分配的公平)。关闭这个参数(设置为0)将忽略target_latency的值。这将使系统中的进程完全按照时间片方式进行IO资源分配。这个开关默认是打开的。我们已经知道cfq设计上有“空转”(idling)这个概念,目的是为了可以让连续的读写操作尽可能多的合并处理,减少磁头的寻址操作以便增大吞吐量。如果有进程总是很快的进行顺序读写,那么它将因为cfq的空转等待命中率很高而导致其它需要处理IO的进程响应速度下降,如果另一个需要调度的进程不会发出大量顺序IO行为的话,系统中不同进程IO吞吐量的表现就会很不均衡。就比如,系统内存的cache中有很多脏页要写回时,桌面又要打开一个浏览器进行操作,这时脏页写回的后台行为就很可能会大量命中空转时间,而导致浏览器的小量IO一直等待,让用户感觉浏览器运行响应速度变慢。这个low_latency主要是对这种情况进行优化的选项,当其打开时,系统会根据target_latency的配置对因为命中空转而大量占用IO吞吐量的进程进行限制,以达到不同进程IO占用的吞吐量的相对均衡。这个开关比较合适在类似桌面应用的场景下打开。target_latency:当low_latency的值为开启状态时,cfq将根据这个值重新计算每个进程分配的IO时间片长度。quantum:这个参数用来设置每次从cfq_queue中处理多少个IO请求。在一个队列处理事件周期中,超过这个数字的IO请求将不会被处理。这个参数只对同步的请求有效。slice_sync:当一个cfq_queue队列被调度处理时,它可以被分配的处理总时间是通过这个值来作为一个计算参数指定的。公式为:time_slice = slice_sync + (slice_sync/5 * (4 - prio))。这个参数对同步请求有效。slice_async:这个值跟上一个类似,区别是对异步请求有效。slice_async_rq:这个参数用来限制在一个slice的时间范围内,一个队列最多可以处理的异步请求个数。请求被处理的最大个数还跟相关进程被设置的io优先级有关。1.3 cfq的IOPS模式我们已经知道,默认情况下cfq是以时间片方式支持的带优先级的调度来保证IO资源占用的公平。高优先级的进程将得到更多的时间片长度,而低优先级的进程时间片相对较小。当我们的存储是一个高速并且支持NCQ(原生指令队列)的设备的时候,我们最好可以让其可以从多个cfq队列中处理多路的请求,以便提升NCQ的利用率。此时使用时间片的分配方式分配资源就显得不合时宜了,因为基于时间片的分配,同一时刻最多能处理的请求队列只有一个。这时,我们需要切换cfq的模式为IOPS模式。切换方式很简单,就是将slice_idle=0即可。内核会自动检测你的存储设备是否支持NCQ,如果支持的话cfq会自动切换为IOPS模式。另外,在默认的基于优先级的时间片方式下,我们可以使用ionice命令来调整进程的IO优先级。进程默认分配的IO优先级是根据进程的nice值计算而来的,计算方法可以在man ionice中看到,这里不再废话。2、deadline:最终期限调度deadline调度算法相对cfq要简单很多。其设计目标是:在保证请求按照设备扇区的顺序进行访问的同时,兼顾其它请求不被饿死,要在一个最终期限前被调度到。我们知道磁头对磁盘的寻道是可以进行顺序访问和随机访问的,因为寻道延时时间的关系,顺序访问时IO的吞吐量更大,随机访问的吞吐量小。如果我们想为一个机械硬盘进行吞吐量优化的话,那么就可以让调度器按照尽量复合顺序访问的IO请求进行排序,之后请求以这样的顺序发送给硬盘,就可以使IO的吞吐量更大。但是这样做也有另一个问题,就是如果此时出现了一个请求,它要访问的磁道离目前磁头所在磁道很远,应用的请求又大量集中在目前磁道附近。导致大量请求一直会被合并和插队处理,而那个要访问比较远磁道的请求将因为一直不能被调度而饿死。deadline就是这样一种调度器,能在保证IO最大吞吐量的情况下,尽量使远端请求在一个期限内被调度而不被饿死的调度器。

一文读懂Linux任务间调度原理和整个执行过程

在前文中,我们分析了内核中进程和线程的统一结构体task_struct,并分析进程、线程的创建和派生的过程。在本文中,我们会对任务间调度进行详细剖析,了解其原理和整个执行过程。由此,进程、线程部分的大体框架就算是介绍完了。本节主要分为三个部分:Linux内核中常见的调度策略,调度的基本结构体以及调度发生的整个流程。下面将详细展开说明。 Linux 作为一个多任务操作系统,将每个 CPU 的时间划分为很短的时间片,再通过调度器轮流分配给各个任务使用,因此造成多任务同时运行的错觉。为了维护 CPU 时间,Linux 通过事先定义的节拍率(内核中表示为 HZ),触发时间中断,并使用全局变量 Jiffies 记录了开机以来的节拍数。每发生一次时间中断,Jiffies 的值就加 1。节拍率 HZ 是内核的可配选项,可以设置为 100、250、1000 等。不同的系统可能设置不同的数值,可以通过查询 /boot/config 内核选项来查看它的配置值。 Linux的调度策略主要分为实时任务和普通任务。实时任务需求尽快返回结果,而普通任务则没有较高的要求。在前文中我们提到了task_struct中调度策略相应的变量为policy,调度优先级有prio, static_prio, normal_prio, rt_priority几个。优先级其实就是一个数值,对于实时进程来说,优先级的范围是 0 99;对于普通进程,优先级的范围是 100 139。数值越小,优先级越高。 实时调度策略主要包括以下几种 普通调度策略主要包括以下几种: 首先,我们需要一个结构体去执行调度策略,即sched_class。该类有几种实现方式 普通任务调度实体源码如下,这里面包含了 vruntime 和权重 load_weight,以及对于运行时间的统计。 在调度时,多个任务调度实体会首先区分是实时任务还是普通任务,然后通过以时间为顺序的红黑树结构组合起来,vruntime 最小的在树的左侧,vruntime最多的在树的右侧。以CFS策略为例,则会选择红黑树最左边的叶子节点作为下一个将获得 CPU 的任务。而这颗红黑树,我们称之为运行时队列(run queue),即struct rq。 其中包含结构体cfs_rq,其定义如下,主要是CFS调度相关的结构体,主要有权值相关变量、vruntime相关变量以及红黑树指针,其中结构体rb_root_cached即为红黑树的节点 对结构体dl_rq有类似的定义,运行队列由红黑树结构体构成,并按照deadline策略进行管理 对于实施队列相应的rt_rq则有所不同,并没有用红黑树实现。 下面再看看调度类sched_class,该类以函数指针的形式定义了诸多队列操作,如 调度类分为下面几种: 队列操作中函数指针指向不同策略队列的实际执行函数函数,在linux/kernel/sched/目录下,fair.c、idle.c、rt.c等文件对不同类型的策略实现了不同的函数,如fair.c中定义了 以选择下一个任务为例,CFS对应的是pick_next_task_fair,而rt_rq对应的则是pick_next_task_rt,等等。 由此,我们来总结一下: 有了上述的基本策略和基本调度结构体,我们可以形成大致的骨架,下面就是需要核心的调度流程将其拼凑成一个整体,实现调度系统。调度分为两种,主动调度和抢占式调度。 说到调用,逃不过核心函数schedule()。其中sched_submit_work()函数完成当前任务的收尾工作,以避免出现如死锁或者IO中断等情况。之后首先禁止抢占式调度的发生,然后调用__schedule()函数完成调度,之后重新打开抢占式调度,如果需要重新调度则会一直重复该过程,否则结束函数。 而__schedule()函数则是实际的核心调度函数,该函数主要操作包括选取下一进程和进行上下文切换,而上下文切换又包括用户态空间切换和内核态的切换。具体的解释可以参照英文源码注释以及中文对各个步骤的注释。 其中核心函数是获取下一个任务的pick_next_task()以及上下文切换的context_switch(),下面详细展开剖析。首先看看pick_next_task(),该函数会根据调度策略分类,调用该类对应的调度函数选择下一个任务实体。根据前文分析我们知道,最终是在不同的红黑树上选择最左节点作为下一个任务实体并返回。 下面来看看上下文切换。上下文切换主要干两件事情,一是切换任务空间,也即虚拟内存;二是切换寄存器和 CPU 上下文。关于任务空间的切换放在内存部分的文章中详细介绍,这里先按下不表,通过任务空间切换实际完成了用户态的上下文切换工作。下面我们重点看一下内核态切换,即寄存器和CPU上下文的切换。 switch_to()就是寄存器和栈的切换,它调用到了 __switch_to_asm。这是一段汇编代码,主要用于栈的切换, 其中32位使用esp作为栈顶指针,64位使用rsp,其他部分代码一致。通过该段汇编代码我们完成了栈顶指针的切换,并调用__switch_to完成最终TSS的切换。注意switch_to中其实是有三个变量,分别是prev, next, last,而实际在使用时,我们会对last也赋值为prev。这里的设计意图需要结合一个例子来说明。假设有ABC三个任务,从A调度到B,B到C,最后C回到A,我们假设仅保存prev和next,则流程如下 最终调用__switch_to()函数。该函数中涉及到一个结构体TSS(Task State Segment),该结构体存放了所有的寄存器。另外还有一个特殊的寄存器TR(Task Register)会指向TSS,我们通过更改TR的值,会触发硬件保存CPU所有寄存器在当前TSS,并从新的TSS读取寄存器的值加载入CPU,从而完成一次硬中断带来的上下文切换工作。系统初始化的时候,会调用 cpu_init()给每一个 CPU 关联一个 TSS,然后将 TR 指向这个 TSS,然后在操作系统的运行过程中,TR 就不切换了,永远指向这个 TSS。当修改TR的值得时候,则为任务调度。 更多Linux内核视频教程文本资料免费领取后台私信【 内核大礼包 】自行获取。 在完成了switch_to()的内核态切换后,还有一个重要的函数finish_task_switch()负责善后清理工作。在前面介绍switch_to三个参数的时候我们已经说明了使用last的重要性。而这里为何让prev和last均赋值为prev,是因为prev在后面没有需要用到,所以节省了一个指针空间来存储last。 至此,我们完成了内核态的切换工作,也完成了整个主动调度的过程。 抢占式调度通常发生在两种情况下。一种是某任务执行时间过长,另一种是当某任务被唤醒的时候。首先看看任务执行时间过长的情况。 该情况需要衡量一个任务的执行时间长短,执行时间过长则发起抢占。在计算机里面有一个时钟,会过一段时间触发一次时钟中断,通知操作系统时间又过去一个时钟周期,通过这种方式可以查看是否是需要抢占的时间点。 时钟中断处理函数会调用scheduler_tick()。该函数首先取出当前CPU,并由此获取对应的运行队列rq和当前任务curr。接着调用该任务的调度类sched_class对应的task_tick()函数进行时间事件处理。 以普通任务队列为例,对应的调度类为fair_sched_class,对应的时钟处理函数为task_tick_fair(),该函数会获取当前的调度实体和运行队列,并调用entity_tick()函数更新时间。 在entity_tick()中,首先会调用update_curr()更新当前任务的vruntime,然后调用check_preempt_tick()检测现在是否可以发起抢占。 check_preempt_tick() 先是调用 sched_slice() 函数计算出一个调度周期中该任务运行的实际时间 ideal_runtime。sum_exec_runtime 指任务总共执行的实际时间,prev_sum_exec_runtime 指上次该进程被调度时已经占用的实际时间,所以 sum_exec_runtime - prev_sum_exec_runtime 就是这次调度占用实际时间。如果这个时间大于 ideal_runtime,则应该被抢占了。除了这个条件之外,还会通过 __pick_first_entity 取出红黑树中最小的进程。如果当前进程的 vruntime 大于红黑树中最小的进程的 vruntime,且差值大于 ideal_runtime,也应该被抢占了。 如果确认需要被抢占,则会调用resched_curr()函数,该函数会调用set_tsk_need_resched()标记该任务为_TIF_NEED_RESCHED,即该任务应该被抢占。 某些任务会因为中断而唤醒,如当 I/O 到来的时候,I/O进程往往会被唤醒。在这种时候,如果被唤醒的任务优先级高于 CPU 上的当前任务,就会触发抢占。try_to_wake_up() 调用 ttwu_queue() 将这个唤醒的任务添加到队列当中。ttwu_queue() 再调用 ttwu_do_activate() 激活这个任务。ttwu_do_activate() 调用 ttwu_do_wakeup()。这里面调用了 check_preempt_curr() 检查是否应该发生抢占。如果应该发生抢占,也不是直接踢走当前进程,而是将当前进程标记为应该被抢占。 由前面的分析,我们知道了不论是是当前任务执行时间过长还是新任务唤醒,我们均会对现在的任务标记位_TIF_NEED_RESCUED,下面分析实际抢占的发生。真正的抢占还需要一个特定的时机让正在运行中的进程有机会调用一下 __schedule()函数,发起真正的调度。 实际上会调用__schedule()函数共有以下几个时机 从系统调用返回用户态:以64位为例,系统调用的链路为do_syscall_64->syscall_return_slowpath->prepare_exit_to_usermode->exit_to_usermode_loop。在exit_to_usermode_loop中,会检测是否为_TIF_NEED_RESCHED,如果是则调用__schedule() 内核态启动:内核态的执行中,被抢占的时机一般发生在 preempt_enable() 中。在内核态的执行中,有的操作是不能被中断的,所以在进行这些操作之前,总是先调用 preempt_disable() 关闭抢占,当再次打开的时候,就是一次内核态代码被抢占的机会。preempt_enable() 会调用 preempt_count_dec_and_test(),判断 preempt_count 和 TIF_NEED_RESCHED 是否可以被抢占。如果可以,就调用 preempt_schedule->preempt_schedule_common->__schedule 进行调度。 u2003u2003 本文分析了任务调度的策略、结构体以及整个调度流程,其中关于内存上下文切换的部分尚未详细叙述,留待内存部分展开剖析。 1、调度相关结构体及函数实现 2、schedule核心函数

loneliness有什么区别吗?

"lone", "alone", 和 "lonely" 这三个词在英语中都有关于孤独或独自一人的含义,但是它们的使用和含义有一些不同:1. "Lone":这个词是形容词,通常用来形容只有一个或者没有伴侣的人或者事物。例如,"a lone traveler"(一个独自旅行的人),"a lone wolf"(孤独的狼,或者形容一个独行侠的人)。1. "Alone":这个词可以是形容词也可以是副词,用来形容没有其他人或者事物在一起,或者没有帮助的情况。例如,"I am alone"(我独自一人),"He did it alone"(他独自一人完成了这个)。3. "Lonely":这个词是形容词,不只是形容独自一人,而是有一种孤独,希望有伴的情绪在里面。例如,"I feel lonely"(我感到孤独)。所以,"lone" 和 "alone" 更侧重于描述物理上的独自一人,而 "lonely" 更侧重于描述情感上的孤独或者寂寞。

loneliness和alone还有lonely的区别?

"lone", "alone", 和 "lonely" 这三个词在英语中都有关于孤独或独自一人的含义,但是它们的使用和含义有一些不同:1. "Lone":这个词是形容词,通常用来形容只有一个或者没有伴侣的人或者事物。例如,"a lone traveler"(一个独自旅行的人),"a lone wolf"(孤独的狼,或者形容一个独行侠的人)。1. "Alone":这个词可以是形容词也可以是副词,用来形容没有其他人或者事物在一起,或者没有帮助的情况。例如,"I am alone"(我独自一人),"He did it alone"(他独自一人完成了这个)。3. "Lonely":这个词是形容词,不只是形容独自一人,而是有一种孤独,希望有伴的情绪在里面。例如,"I feel lonely"(我感到孤独)。所以,"lone" 和 "alone" 更侧重于描述物理上的独自一人,而 "lonely" 更侧重于描述情感上的孤独或者寂寞。

唯爱玲。用这三个字取英文名。我只知道Va是唯爱的意思,后面那个玲应该怎么写呢。是valin这样吗?

valin就挺好

celine的luggage 包和boston包有什么区别

是笑脸包和波士顿包,款号不一样的。711bao美乐皮具

嵌入式Linux系统的root密码忘了kos怎么才能找回来?

我也有这问题,不知道怎么弄,你要是有办法了,说一声啊。

外星人Alineware电脑贵不贵?

外星人电脑贵呀 看你能接受的价位多少 最便宜的万元起步 外星人电脑真的挺好用 外星人电脑不管是显卡和处理器都是yyds

如何在Linux Mint Cinnamon启用桌面共享

我试着在Linux Mint 17 Cinnamon桌面上通过Vino VNC服务器(vino-server)启用桌面共享。但是,我发现用来配置vino-server(如,共享选项,安全,通知开/关)的vino首选项工具已经不复存在了。同时,我也的Cinnamon桌面上也找不到共享菜单。我怎样才能在最新的Linux Mint 17 Cinnamon桌面上通过vino-server配置桌面共享?最新的Linux Mint 17 Cinnamon桌面附带了预安装用于VNC桌面共享的vino-server,但是它报告说桌面共享菜单丢失了。一个配置vino-server并启用桌面共享的可选方式,是使用dconf-editor的图形界面。首先安装dconf-editor:$ sudo apt-get install dconf-editor启动dconf-editor。$ dconf-editor在dconf-editor的左边面板中导航到“org->gnome->desktop->remote-access”,然后你将会看到各种各样的桌面共享选项。最重要的是,点击“enabled”来激活桌面远程访问。除此之外,你还可以自定义其它选项。例如,你可以通过修改以下字段来启用VNC密码验证:authentication-methods: 设置为 ["vnc"]vnc-password: 将你喜欢的密码修改为Base64编码的字符串。在本例中,我们选择“password”为VNC密码,它的Base64编码字符串为“cGFzc3dvcmQ=”。你也可以选择启用其它选项:notify-on-connect: 当vino-server接收到连接请求时显示桌面通知。prompt-enabled: 远程用户不允许通过VNC工具访问桌面,除非VNC请求被该桌面的拥有者许可。排障当启动vino-server时,我碰到了下面的错误。** (vino-server:4280): WARNING **: The desktop sharing service is not enabled, so it should not be run.要启用桌面共享服务,请使用上面讲过的dconf-editor。 也可以选择运行以下命令:# gsettings set org.gnome.Vino enabled true

linux系统下,1.新建用户组jsj 2新建用户jsj1,jsj2并设置相应密码,把jsj1,

sudo groupadd jsjsudo useradd -g jsj jsj1sudo useradd -g jsj jsj2sudo passwd jsj1sudo passwd jsj2

Protel99软件中line和wire wire和bus , bus Entry的区别

用line画线是没有电气连接属性的。用wire 画的线是有电气连接属性的,相当于现实中的导线。用bus画的是总线,就是多条wire并在一起的。busEntry是画总线的分线,点的一端连总线。总线其实没有实际意义只是好理解,主要考网络号的对应连接

line和wire的区别和用法?

wire 单指特定的一条线/电线/金属丝 等等line 除了有统称 线的意思之外,还指整个含有这种线的系统brake line: 刹车系统brake wire:刹车线刹车线:brake cables油门线:accelerator cable对车不是很熟悉,所以不知道剩下的是什么,怎么说。

wire 和 line 都有电线的意思 怎么区别呢

wire 单指特定的一条线/电线/金属丝 等等line 除了有统称 线的意思之外,还指整个含有这种线的系统brake line: 刹车系统brake wire:刹车线

line和wire的区别和用法?

wire单指特定的一条线/电线/金属丝等等line除了有统称线的意思之外,还指整个含有这种线的系统brakeline:刹车系统brakewire:刹车线刹车线:brakecables油门线:acceleratorcable对车不是很熟悉,所以不知道剩下的是什么,怎么说。

line和wire的区别和用法?

wire单指特定的一条线/电线/金属丝等等line除了有统称线的意思之外,还指整个含有这种线的系统brakeline:刹车系统brakewire:刹车线刹车线:brakecables油门线:acceleratorcable对车不是很熟悉,所以不知道剩下的是什么,怎么说。

First-line managers是指哪些人?

基层管理者(First-line managers)管理者是管理行为过程的主体,管理者一般由拥有相应的权力和责任,具有一定管理能力从事现实管理活动的人或人群组成。按管理者在组织中所处的地位划分,管理者可分为:高层管理者、中层管理者和基层管理者。基层管理者又称一线管理者,具体指工厂里的班组长、小组长等。他们的主要职责是传达上级计划、指示,直接分配每一个成员的生产任务或工作任务,随时协调下属的活动,控制工作进度,解答下属提出的问题,反映下属的要求。他们工作的好坏,直接关系到组织计划能否落实,目标能否实现,所以,基层管理者在组织中有着十分重要的作用。对基层管理者的技术操作能力要求较高,但并不要求其拥有统筹全局的能力。基层管理者应具备的能力“队长”一般都具有非常强地组织能力,由技术高或德高望重的队员担任。基层管理者又好象大树上的结点,将树根部的养分分解、传递给小枝杈,因而基层管理者的作用又可以概括为“分解、传递”。既然基层管理者扮演的是队长的角色,那么相应的应具备这样一些能力:1、过硬的业务能力。因为基层管理者不同于中层管理者,不需要对本部门的发展进行过多地规划,而只需完成所负责的小部门工作职能。基层管理者即是管理者,同时又肩负了具体的工作和事务,所以个人过硬的业务能力和素质是在组织中“让人心服口服”的前提。同时,企业的各种业务培训一般也是通过基层管理者进行的,所以业务能力对基层管理人员来说非常关键。2、亲和力。既然是基层管理者,就必须与群众打成一片。不能因为自己是个小头目,而拒人千里之外。那么,对于基层管理者来说,亲和力并简单指与同事在一起说说笑笑。为了让“手下”干事痛快,而且心悦诚服地服“管教”,必须具有以下几种“心”:  1)尊重的心:基层管理者必须尊重自己组织中的每个员工。所谓“想人怎样待己便应该怎样待人”,尊重是赢得真诚的前提。尽管在组织中,每个员工的身世背景、家庭可能各有不同,但是以平等的心对待每个人,才能谋求一个融洽的氛围。  2)关心的心:基层管理者直接接触地就是一线员工,因而他们的“疾苦”、“心声”基层管理者知道得最清楚。关心才能显示出自己的仁爱之心。  3)体恤的心:既然有了关心,就应该在他们出现个人问题时,体恤他们。同时,学会换位思考,所谓“己所不欲勿施于人”。3、团队建设能力。基层管理者除了要有过硬的业务能力,那么体现管理者魅力和价值的就是团队建设的能力。一个人的业绩可能非常优秀,但是只注重个人的业绩而忽视了团队,充其量只是一个业务精英。如果将团队发挥巨大的效能作用,便是一个管理者的最大喜悦。4、领导力基层管理者虽然是“管理者”,但由于本身所处的角色,需要更多发挥自己的领导力而非行政赐予的管理能力,之间的区别在于:  1)管理者一般是被任命的,其影响力来自职位所赋予的正式权力。而领导者可以被任命,也可以是从群体中产生的,影响力主要来自非职位权力。  2)管理可以运用职权迫使人们去从事某项工作,而领导者是依靠个人的魅力去影响他人。  3)管理者是依靠制度、管理工具达到目的;而领导者依靠的是远景规划、激励去实现目标。5、与上司相处的能力授命于基层管理者的是上司,因而保持与上司良好的沟通是获得进一步提升的关键。有很多基层管理者可以赢得下属的尊重,业务能力也非常优秀,却无法获得进一步提升满足自己的更大追求,原因是往往忽视了与上司的沟通。  1)让上司知道你每天都在干什么。这点非常关键,第一是尊重,第二避免滋生出太多的想法,如想抢位、在暗中捣乱、轻视等等。  2)征询上司的意见获得支持。有时明明可以走的捷径,但因为忽视了与上司的沟通,而走了弯路。所以在一些问题上多听听上司的意见没有错。球场上“队长”精湛的球技,以及较强的组织、把控能力,令人叹服。那么对于刚步入社会不久,没有多少工作经验而成为一名管理者的年轻人来说,受到领导的器重,确实是一个难得的机遇。要想成为一名“一呼百应”地队长,除了迅速提高自己的业务能力,更要在日常工作中的不断培养自己的工作技巧。

全新现代KONA官图发布 将推出燃油/混动/纯电/N Line多款动力

易车讯 现代汽车全新一代Kona官图发布,新车基于电动汽车的未来设计,将提供燃油、混动、纯电、N Line多款动力版本。信息显示,车辆长度增加150毫米至4355毫米,轴距增加60毫米,宽度增加25毫米;已发展成为一款更大胆的城市SUV,为用户提供了最大化的“生活空间”。值得注意的是,车辆基于纯电车型开始设计研发,然后衍生出燃油、混动和N Line等车型。虽然共享架构,但风格上都具有各自的鲜明特点。全新Kona的前后日间行车灯非常醒目,贯穿式设计让整体感觉特别简洁。前牌照架周围的格栅样式,是区别不同动力车款最直观的部分。通过现有官图来看,车辆具有双12.3英寸的联屏、氛围灯、天窗等配置,副驾驶座椅为手动调节,后排地板全平。纯电动力版本轮圈为19英寸,N Line版本可选黑色细节装饰和双出排气等。更多信息,现代汽车将在未来几个月内公布。作为参考,此前现代Kona N曾与伊兰特N一起,已在国内进行了针对媒体的车辆展示。易车超级评测体系重磅发布,为用户带来当前市场中热门畅销新车的全方位实用评测,彻底解决你的选车、购车、用车疑惑。

linux下的 数据库 有哪些?

主流的数据库都有,oracle sybase mysql 等

online retailer是什么意思

网络网上零售商,传统零售商建网站销售,网络零售商

Blinded By The Sun 歌词

歌曲名:Blinded By The Sun歌手:Gym Class Heroes专辑:Patches From The Quilt - EpGym Class Heroes - Blinded By The SunYou told me it"s the truthBut I"m still afraidI"m not the oneThat would jump the gunIf I had proofI"d take off my shadesAnd be blinded by the sunOne lie, two liesI shoulda said shoe fliesShame on meI usually see through liesSaid you loved me, yeah rightI thought we were air tightYou were playing foulIt was far from a fair fightI hung onto your every wordSweetest shit I ever heardI even made you pinky swearJust so I was reassuredThe rumors started gettin backThat so and so was hittin" thatSilly me for being suchA "natic for that kitty catYou told me it"s the truthBut I"m still afraidI"m not the oneThat would jump the gunIf I had proofI"d take off my shadesAnd be blinded by the sunYou said you were in loveBut the games you playedI hope that you"re having funYou see I need youTo take off my shadesAnd be blinded by the sunThree lies, four liesYou shoulda been a tour guideThe way you lead me onKnowing I was one of four guysSaid you loved me, okayWhere were you the other day?Your car was parked at 38thBut you wereAt your mothers place?Your mother lives on BroadwayI followed you all dayI called but you ignored itWhen you kissed himIn the hallwayCall me crazy, call me oddCall me what you want toBut Karma is a bitchI pray to GodShe always haunts youYou told me it"s the truthBut I"m still afraidI"m not the oneThat would jump the gunIf I had proofI"d take off my shadesAnd be blinded by the sunYou said you were in loveBut the games you playedI hope that you"re having funYou see I need youTo take off my shadesAnd be blinded by the sunI wear my sunglasses at night, so I can, so I canI wear my sunglasses at night, so I can, so I canI wear my sunglasses at night, so I can, so I canI wear my sunglasses at night, so I can, so I canYou told me it"s the truthBut I"m still afraidI"m not the oneThat would jump the gunIf I had proofI"d take off my shadesAnd be blinded by the sunYou said you were in loveBut the games you playedI hope that you"re having funYou see I need youTo take off my shadesAnd be blinded by the sunYou told me it"s the truthBut I"m still afraidI"m not the oneThat would jump the gunIf I had proofI"d take off my shadesAnd be blinded by the sunYou said you were in loveBut the games you playedI hope that you"re having funYou see I need youTo take off my shadesAnd be blinded by the sunhttp://music.baidu.com/song/12322527

Simulink中SIL测试功能怎么使用

一般模型分为两个,一个是测试环境模型,提供输入信号源,设置Normal模式;一个是被测模型,存储为独立的slx;在测试环境模型中使用两个Model Referrence引用被测模型,并设置其中一个为Normal模式,另一个为SIL模式,然后进行仿真。

Redhat linux常用的命令有哪些?

一. 启动,关机,登入,登出相关命令 <login> 登录 <logout> 登出 <exit> 登出 <shutdown> 停止系统 <halt> 停止系统 <reboot> 重启动 <poweroff> 切断电源 <sync> 把内存里的内容写入磁盘 <lilo> 安装lilo启动管理程序 <grub> 安装lilo启动管理程序 二. Shell相关命令 <chsh> 切换Shell <history> 显示命令履历 <alias> 设置命令别名 <unalias> 取消命令别名 <which> 显示命令所在位置 <type> 查询命令种类 <echo> 显示字符串或者变量内容 <set> 设置/显示Shell变量 <printenv> 显示环境变量 <export> 设置环境变量 <env> 设置临时环境变量 <unset> 释放环境变量 <setenv> 设置环境变量 <unsetenv> 释放环境变量 <source> 执行文件当中的命令 <man> 查询命令手册 <info> 查询超文本命令手册 <whatis> 显示命令简介 <apropos> 通过关键字查询手册 三. 用户管理相关命令 <su> 切换到其他用户 <useradd> 追加用户 <adduser> 追加用户 <userdel> 删除用户 <usermod> 修改用户设置 <chfn> 修改用户私人信息 <groupadd> 追加组 <groupdel> 删除组 <groupmod> 修改组设置 <passwd> 更改密码 <whoami> 显示用户名 <logname> 显示登录用户帐号 <users> 显示所有登录用户信息 <who> 查询登录用户信息 <w> 查询登录用户信息 <id> 显示指定用户的ID信息 <groups> 显示指定用户的所属组 <finger> 显示指定用户的个人信息 <mesg> 开关与他人收发消息 <write> 给其他用户发消息 <wall> 给所有用户发消息 <talk> 和其他用户聊天 四. 系统消息相关命令 <date> 显示/设置当前时间 <uptime> 显示系统运行时间 <arch> 显示机器的核心构架(如i386) <uname> 显示操作系统信息 <tty> 显示终端名 <last> 显示登录/登出在履历 <lastb> 显示非法登录信息 <dumpkeys> 显示当前键盘配置 <loadkeys> 变更键盘配置 <df> 查询磁盘使用信息 <du> 查询磁盘使用信息 <dmesg> 显示系统启动消息 <script> 保存输入输出到文件 五. 文件操作相关命令 <ls> 显示文件列表 <tree> 显示目录树 <pwd> 显示当前路径 <cd> 更改当前路径 <pushd> 追加路径到目录堆栈 <popd> 从目录堆栈删除路径 <dirs> 显示目录堆栈的内容 <mkdir> 创建路径 <rmdir> 删除路径 <cp> 复制文件/目录 <rm> 删除文件/目录 <mv> 移动文件/目录,修改文件名 <chown> 更改文件/目录的所有者 <chgrp> 修改文件/目录的所有组 <chmod> 修改文件/目录的权限 <touch> 更改文件时间 <ln> 建立文件/目录链接 <find> 查找文件 <whereis> 显示文件存在的路径名 <file> 查询文件种类 <size> 查询文件大小 六. 文件编辑相关命令 <cat> 显示文件内容 <tee> 输出到文件和屏幕 <more> 分屏显示文件内容 <less> 分屏显示文件内容 <head> 显示文件头部内容 <tail> 显示文件尾部内容 <fold> 折叠显示长行 <sort> 排列文件的行 <cmp> 比较文件内容 <diff> 显示文件差异 <nkf> 更改日语文件编码 <dd> 变更文件之后复制 <wc> 统计文本单词数,文件大小等 <split> 分割文件 <paste> 以行连接文件 <join> 以字段连接文件 <grep> 查询文字 <uniq> 过滤重复部分显示文件内容 <tr> 替换文字 <sed> 替换文字 七. 压缩/解压缩相关命令 <ar> 压缩/解压缩文件 <tar> 压缩/解压缩文件 <compress> 压缩/解压缩文件 <uncompress> 解压缩 <gzip> 压缩/解压缩文件 <gunzip> 解压缩 <zcat> 显示压缩文件的内容 <lha> 压缩/解压缩文件 <uuencode> 把二进制文件编码为文本文件 <uudecode> 把经过编码的文本文件还原为二进制文件 八. MS-DOS工具集[mtools]命令 <mdir> 显示文件列表 <mcd> 改变当前目录 <mmd> 新建目录 <mrd> 删除目录 <mdeltree> 删除目录树 <mcopy> 复制文件 <mdel> 删除文件 <mmove> 移动文件 <mren> 更改文件或目录名 <mattrib> 修改文件属性 <mtype> 显示文件内容 <mdu> 查询文件或目录大小 <minfo> 显示磁盘信息 <mformat> 以MS-DOS方式格式化磁盘 <mlabel> 设置磁盘标签 九. 控制外部设备相关命令 <mount> mount上设备 <umount> 解除已经mount上的设备 <eject> 弹出(CD/DVD等) <fdformat> 格式化软盘 <fdisk> 配置/显示硬盘分区 <mkfs> 格式化磁盘分区 <fsck> 检查/修复磁盘错误 <lpr> 打印到打印机 <lprm> 中断打印任务 <lpq> 显示打印任务的状态 <lpc> 管理/控制打印任务 <ifconfig> 显示/设定NIC配置 十. 进程及任务管理相关命令 <ps> 显示正在运行的进程 <jobs> 显示后台运行任务 <fg> 把任务切换到前台 <bg> 把任务切换到后台 <kill> 中止进程或任务 <killall> 中止进程或任务 <wait> 等待进程或任务的结束 <at> 设置定时执行任务 <atq> 显示尚未执行的任务 <atrm> 删除定时执行任务 <batch> 在系统负荷减轻的时候执行任务 <nice> 改变优先度并执行任务 <nohup> 在后台执行任务,Logout之后也不退出 <sleep> 休眠一定的时间 十一. 网络管理相关命令 <netstat> 显示当前网络连接状况 <route> 显示/设置路由 <host> 显示网络主机情况 <hostname> 显示/设置当前主机的名字 <ping> 确认和远程机器的连接情况 <traceroute> 显示路由信息 <rwho> 查询网上机器的登陆用户 <ruptime> 查询网上机器的系统运行时间 <rlogin> 登陆到远程机器 <telnet> 用telnet登陆到远程机器 <rsh> 给远程机器发送命令 <rcp> 在远程机器之间复制文件 <mail> 收取邮件 <sendmail> 发送邮件 <mailq> 确认邮件队列 <ftp> 用ftp传输文件 十二. 其他命令 <cal> 显示日历 <clear> 清屏 <gcc> 编译C语言代码 <as> 汇编 <bc> 计算 <rpm> Redhat的包管理 <dpkg> Debian的包管理 <installpkg> Slackware的包安装(删除命令则是removepkg) <XF86Setup,turboxfg,Xconfigurator> 配置 X 服务器 <startx> 启动 X-Window 系统 附:组合命令 重定向,如 $ ls -l /bin > ls-output $ more ls-output 管道命令,如 $ cat file1 file2 | sort | uniq 经常被用于管道的命令 awk, fold, grep, head, nnkf, pr, sed, sort, tail, tee, tr, uniq, wc

Simulink中SIL测试功能怎么使用

一般模型分为两个,一个是测试环境模型,提供输入信号源,设置Normal模式;一个是被测模型,存储为独立的slx;在测试环境模型中使用两个Model Referrence引用被测模型,并设置其中一个为Normal模式,另一个为SIL模式,然后进行仿真。

Simulink中SIL测试功能怎么使用

一般模型分为两个,一个是测试环境模型,提供输入信号源,设置Normal模式; 一个是被测模型,存储为独立的slx; 在测试环境模型中使用两个Model Referrence引用被测模型,并设置其中一个为Normal模式,另一个为SIL模式,然后进行仿真。

linux下如何解压文件

tar zxvf u````````````.tgz

simulink一跑sil就崩溃

以下是一些造成的原因和解决方法。1、SIL模式下,Simulink会将模型转换为C代码并进行编译,模型中存在代码错误,编译过程会失败并导致Simulink崩溃。可以检查模型中的代码并修复错误。2、编译器需要占用大量内存,计算机内存不足,编译过程会失败并导致Simulink崩溃。增加计算机的内存或关闭其它占用内存的程序。3、Simulink使用编译器将模型转换为C代码,编译器存在问题,会导致Simulink崩溃。更新编译器或使用其它编译器。4、SIL模式下,模型设置会影响编译过程。检查模型设置并确保其正确。5、Simulink版本存在问题,导致SIL模式下崩溃。更新Simulink版本或使用其它版本。

在linux F10中,在桌面有一个11.XLS文件,我想用命令压缩成gz格式的,什么命令阿

用bzip2或gzip都可以,在终端中man bzip2或man gzip都可以获得帮助如果你不在桌面的路径下就必须写绝对路径,文件名和后缀都要写.Linux下常见打包、压缩、解压命令:.tar解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName注:tar是打包,不是压缩———————————————.gz解压1:gunzip FileName.gz解压2:gzip -d FileName.gz压缩:gzip FileName———————————————.tar.gz 和 .tgz解压:tar zxvf FileName.tar.gz压缩:tar zcvf FileName.tar.gz DirName———————————————.bz2解压1:bzip2 -d FileName.bz2解压2:bunzip2 FileName.bz2压缩: bzip2 -z FileName———————————————.tar.bz2解压:tar jxvf FileName.tar.bz2压缩:tar jcvf FileName.tar.bz2 DirName———————————————.bz解压1:bzip2 -d FileName.bz解压2:bunzip2 FileName.bz———————————————.tar.bz解压:tar jxvf FileName.tar.bz———————————————.Z解压:uncompress FileName.Z压缩:compress FileName———————————————.tar.Z解压:tar Zxvf FileName.tar.Z压缩:tar Zcvf FileName.tar.Z DirName———————————————.zip解压:unzip FileName.zip压缩:zip FileName.zip DirName———————————————.rar解压:rar x FileName.rar压缩:rar a FileName.rar DirName———————————————.lha解压:lha -e FileName.lha压缩:lha -a FileName.lha FileName———————————————.rpm解包:rpm2cpio FileName.rpm | cpio -div———————————————.deb解包:ar p FileName.deb data.tar.gz | tar zxf -———————————————.tar .tgz .tar.gz .tar.Z .tar.bz .tar.bz2 .zip .cpio .rpm .deb .slp .arj .rar .ace .lha .lzh .lzx .lzs .arc .sda .sfx .lnx .zoo .cab .kar .cpt .pit .sit .sea解压:sEx x FileName.*压缩:sEx a FileName.* FileNamesEx只是调用相关程序,本身并无压缩、解压功能

Simulink中SIL测试功能怎么使用

一般模型分为两个,一个是测试环境模型,提供输入信号源,设置Normal模式; 一个是被测模型,存储为独立的slx; 在测试环境模型中使用两个Model Referrence引用被测模型,并设置其中一个为Normal模式,另一个为SIL模式,然后进行仿真。

在linuxcentos系统里面怎么用命令删除服务

可以使用kill命令杀进程,最常用的就是kill -9 pid号具体查看进程pid可以使用ps -ef|grep 进程名字下面是ps和kill的简单介绍Linux中的ps命令是Process Status的缩写。ps命令用来列出系统中当前运行的那些进程。ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信息,就可以使用top命令。要对进程进行监测和控制,首先必须要了解当前进程的情况,也就是需要查看当前进程,而 ps 命令就是最基本同时也是非常强大的进程查看命令。使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等。总之大部分信息都是可以通过执行该命令得到的。ps 为我们提供了进程的一次性的查看,它所提供的查看结果并不动态连续的;如果想对进程时间监控,应该用 top 工具。kill 命令用于杀死进程。linux上进程有5种状态: 1. 运行(正在运行或在运行队列中等待) 2. 中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号) 3. 不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有中断发生) 4. 僵死(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放) 5. 停止(进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行运行) ps工具标识进程的5种状态码: D 不可中断 uninterruptible sleep (usually IO) R 运行 runnable (on run queue) S 中断 sleeping T 停止 traced or stopped Z 僵死 a defunct (”zombie”) process 1.命令格式:ps[参数]2.命令功能:用来显示当前进程的状态3.命令参数:a 显示所有进程-a 显示同一终端下的所有程序-A 显示所有进程c 显示进程的真实名称-N 反向选择-e 等于“-A”e 显示环境变量f 显示程序间的关系-H 显示树状结构r 显示当前终端的进程T 显示当前终端的所有程序u 指定用户的所有进程-au 显示较详细的资讯-aux 显示所有包含其他使用者的行程 -C<命令> 列出指定命令的状况--lines<行数> 每页显示的行数--width<字符数> 每页显示的字符数--help 显示帮助信息--version 显示版本显示Linux中的kill命令用来终止指定的进程(terminate a process)的运行,是Linux下进程管理的常用命令。通常,终止一个前台进程可以使用Ctrl+C键,但是,对于一个后台进程就须用kill命令来终止,我们就需要先使用ps/pidof/pstree/top等工具获取进程PID,然后使用kill命令来杀掉该进程。kill命令是通过向进程发送指定的信号来结束相应进程的。在默认情况下,采用编号为15的TERM信号。TERM信号将终止所有不能捕获该信号的进程。对于那些可以捕获该信号的进程就要用编号为9的kill信号,强行“杀掉”该进程。 1.命令格式:kill[参数][进程号]2.命令功能:发送指定的信号到相应进程。不指定型号将发送SIGTERM(15)终止指定进程。如果任无法终止该程序可用“-KILL” 参数,其发送的信号为SIGKILL(9) ,将强制结束进程,使用ps命令或者jobs 命令可以查看进程号。root用户将影响用户的进程,非root用户只能影响自己的进程。3.命令参数:-l 信号,若果不加信号的编号参数,则使用“-l”参数会列出全部的信号名称-a 当处理当前进程时,不限制命令名和进程号的对应关系-p 指定kill 命令只打印相关进程的进程号,而不发送任何信号-s 指定发送信号-u 指定用户 注意:1、kill命令可以带信号号码选项,也可以不带。如果没有信号号码,kill命令就会发出终止信号(15),这个信号可以被进程捕获,使得进程在退出之前可以清理并释放资源。也可以用kill向进程发送特定的信号。例如:kill -2 123它的效果等同于在前台运行PID为123的进程时按下Ctrl+C键。但是,普通用户只能使用不带signal参数的kill命令或最多使用-9信号。2、kill可以带有进程ID号作为参数。当用kill向这些进程发送信号时,必须是这些进程的主人。如果试图撤销一个没有权限撤销的进程或撤销一个不存在的进程,就会得到一个错误信息。3、可以向多个进程发信号或终止它们。4、当kill成功地发送了信号后,shell会在屏幕上显示出进程的终止信息。有时这个信息不会马上显示,只有当按下Enter键使shell的命令提示符再次出现时,才会显示出来。5、应注意,信号使进程强行终止,这常会带来一些副作用,如数据丢失或者终端无法恢复到正常状态。发送信号时必须小心,只有在万不得已时,才用kill信号(9),因为进程不能首先捕获它。要撤销所有的后台作业,可以输入kill 0。因为有些在后台运行的命令会启动多个进程,跟踪并找到所有要杀掉的进程的PID是件很麻烦的事。这时,使用kill 0来终止所有由当前shell启动的进程,是个有效的方法。

linux把文件压缩成.tar.gz的命令

01-.tar格式解包:[*******]$ tar xvf FileName.tar打包:[*******]$ tar cvf FileName.tar DirName(注:tar是打包,不是压缩!)02-.gz格式解压1:[*******]$ gunzip FileName.gz解压2:[*******]$ gzip -d FileName.gz压 缩:[*******]$ gzip FileName03-.tar.gz格式解压:[*******]$ tar zxvf FileName.tar.gz压缩:[*******]$ tar zcvf FileName.tar.gz DirName04-.bz2格式解压1:[*******]$ bzip2 -d FileName.bz2解压2:[*******]$ bunzip2 FileName.bz2压 缩: [*******]$ bzip2 -z FileName05-.tar.bz2格式解压:[*******]$ tar jxvf FileName.tar.bz2压缩:[*******]$ tar jcvf FileName.tar.bz2 DirName06-.bz格式解压1:[*******]$ bzip2 -d FileName.bz解压2:[*******]$ bunzip2 FileName.bz07-.tar.bz格式解压:[*******]$ tar jxvf FileName.tar.bz08-.Z格式解压:[*******]$ uncompress FileName.Z压缩:[*******]$ compress FileName09-.tar.Z格式解压:[*******]$ tar Zxvf FileName.tar.Z压缩:[*******]$ tar Zcvf FileName.tar.Z DirName10-.tgz格式解压:[*******]$ tar zxvf FileName.tgz11-.tar.tgz格式解压:[*******]$ tar zxvf FileName.tar.tgz压缩:[*******]$ tar zcvf FileName.tar.tgz FileName12-.zip格式解压:[*******]$ unzip FileName.zip压缩:[*******]$ zip FileName.zip DirName13-.lha格式解压:[*******]$ lha -e FileName.lha压缩:[*******]$ lha -a FileName.lha FileName14-.rar格式解压:[*******]$ rar a FileName.rar压缩:[*******]$ rar e FileName.rar rar请到:http://www.rarsoft.com/download.htm 下载!解压后请将rar_static拷贝到/usr/bin目录(其他由$PATH环境变量指定的目录也行):[*******]$ cp rar_static /usr/bin/rar来自:http://hi.baidu.com/ucdcmqj/blog/item/c48fab59b2c1322c2934f0fd.html

想自学linux,主要是用ARM开发板做项目

鸟哥私房菜----入门linux就没问题了.书中告诉你怎么学linux

Java 8的Streams API和.Net的LINQ使用上最大的不同是什么

Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。 (摘自某博客)Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次Stream不是ORM (对象关系映射)linq有自己的语法,和lambda表达式不同。LINQ,语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展,然后linq能访问多种类型的对象lin的运用有多种:linq to 集合,linqtoxml,txt,doc,sql。。。等等,(ORM组件)然后Stream中的lambda和.net里面的lambda有点类似

Java 8的Streams API和.Net的LINQ使用上最大的不同是什么

完整的LINQ分以下几部分,缺一不可:Lambda ExpressionQuery ExpressionExtension MethodsExpression TreeAnonymous TypesJava除了第一个后面都没有。你可以认为Java的Streams API是一个:无法用Monad形式(没有Query Expression)难以扩展的(没有Extension Methods)无法表达语句结构及动态编译函数(没有Expression Tree)无法借助临时结构减少计算或增强表达能力(没有Anonymous Types)的LINQ。此外,这套API不是加在标准的Iterator和Iterable模型上的(在C#叫IEnumerator和IEnumerable),导致又多了一套Streams模型出来,而又和IO的Stream容易产生混淆,真不知道设计者是怎么想的,搞个Extension Methods出来多好,不光对LINQ有用,简直方便之至。总而言之,Java 8这套给我的感觉就是因为不愿意搞出和C#一样的设计而引入的半吊子东西。当年Lambda表达式的草案是和C#以及Scala一样使用“=>”符号的,结果最后硬要改为“->”真是生怕别人不知道要故意跟C#不同。

请问在物流行业里面Handling fee: USD 20/shipment和Bill fee: USD 20/Bill.分别是什么意思?

handling fee, (操作手续费)BILL FEE, (文件费)

Remedy (Feat. Espen Lind) 歌词

歌曲名:Remedy (Feat. Espen Lind)歌手:Maria Arredondo专辑:Not Going UnderRachael Lampa - Remedy...I know where to goTo heal my heart, to soothe my soulWhen everything-things spinning out of control, I knowI know just living life can get so crazy day and nightBut I""ve got somebody by my side, by my sideEvery time I cry and I wanna hideFeeling like I""m damaged on the insideYou know just what to do.You""ve got what I needYou""re the remedyThat""s why I""m keeping You close, You closeYou know what""s best for meMy only therapyJesus Your love is my hope, my hopeYou""re my remedy, You""re my remedyYou""re my remedyYou""re my remedy, You""re my remedy.On point, off trackOne step forward, two steps backSome days are gonna be just like thatJust like thatYou""re my medicineRelieve my pain again and againAlways take me back no matter where I""ve been, where I""ve beenEvery time I""m hurt and it doesn""t workFeeling like it never could get any worseI go running to You.You""ve got what I needYou""re the remedyThat""s why I""m keeping You close, You closeYou""re my remedyYou know what""s best for meMy only therapyJesus Your love is my hope, my hope.You""ve got what I needYou""re the remedyThat""s why I""m keeping You close, You closeYou""re my remedyYou know what""s best for meMy only therapyJesus Your love is my hope, my hope.And every time I come knocking at Your doorYou make me feel like I""m the only one that You adoreThe only one You do this forThe only one that You call yours, I""m Yours.You""ve got what I needYou""re the remedyThat""s why I""m keeping You close,You""re my remedyYou know what""s best for meMy only therapyJesus Your love is my hope, my hopeYou""re my remedy, You""re my remedyYou""re my remedy, You""re my remedyYou""re my remedyYou""re my remedy, You""re my remedyYou""re my remedy, You""re my remedy.http://music.baidu.com/song/840555

Linux 如何启动/关闭 X 服务?

service gdm3 stop service gdm3 start 在Ubuntu系统中,也可以使用别的命令来完成同样的功能,如下: sudo /etc/init.d/lightdm start sudo /etc/init.d/lightdm stop 如果X服务是在关闭状态,那么想快速的启动X服务,可以使用命令: startx 即可。 支持各种界面 :相较于GDM-GTK,KDM-Qt,LightDM实际上是界面无关性的,因为它设计上就是支持本地图形界面以获得最好的兼容性。因此LightDM现在已经具备了GTK、Qt甚至WebKit的界面,也就是用HTML来做登陆界面。

如何为Kali Linux安装KDE桌面环境

root@Kali:~# apt-get install kde-plasma-desktop需要458 M的额外的磁盘空间。按Y键同意。需要一些时间才能安装完成。它将要求您配置kdm,按回车。选择gdm3作为默认显示管理器现在注销你的系统,选择“KDE Plasma Workspace”选项,然后输入用户名和密码登录。现在Kali Linux的KDE桌面安装好,可以正常使用了。

ssh远程登录linux后如何打开远端桌面

用灰鸽子

linux RH9.0里 KDM,GNOME,GDM,KDE具体的含义。谢谢

什么是窗口管理器、GNOME、KDE、XDM、KDM、GDM 一、窗口管理器1、窗口管理器:它是负责管理窗口的移动、最大化、最小化、改变大小以及关闭等工作2、常见的窗口管理器 1)twm(X.org提供的简单的窗口管理器)2)gnome-wm(gnome提供的窗口管理器)3)kwin(KDE使用的窗口管理器)4)FVWM(一款知名的窗口管理器)===================================================================二、GNOME、KDEGNOME、KDE是桌面系统,是集成了窗口管理器及一些应用程序的套件===================================================================三、XDM、GDM和KDMXDM、GDM、KDM是三种X Window的显示管理器,其功能相当于文本模式下的init、getty和login;当用户输入的正确的用户名和口令后将开启一个会话(1)XDM(默认的X Window System Display Manager)(2)GDM(gnome提供的Display Manager)(3)KDM(KDE提供的Display Manager)

QUEUED FOR MANUAL HANDLING/PNR CANCELLED 什么意思 急!!!

排队等待体力处理/名册取消

linux slave设备 ,slave设备是什么意思,如果放在网络配置中代表什么意思

主设备是master,从设备是slave。主从关系,放网络配置中也是这种。

simulink中zeros(s)/poles(s)是什么意思?就是图中第二行第三个方框表示什么?怎么画出来呢?谢谢了

这个zeros(s)/poles(s)表示零极点增益模型,跟传递函数等价,这里之所以显示这种形式,是因为里面的零点和极点数目较多,不足以在当前模型中的框图中显示出来,如果你利用鼠标把该模块的方框横向拉大,它自然会以要s(s+1)/(s+2)(s+3)等这种形式显示。总之就是显示问题,对模型没影响,它真正代表的还是里面设置的零极点增益值所表达的模型。 希望对你有用并采纳,谢谢!

WebRTC中的Signaling Server是不是起到了一个ICEServer的作用

我认为不是 两个peer要会话就需要把各自的sdp发送到对方,如果两者都在局域网(nat)之后,怎么发送?这时候就需要一个在公网上的能直接访问的中间者来传递消息,在这之前两者都是tcp连接在中间服务器上的。这个中间服务器除了转发sdp,还会传递candidate,它包含stun之后的信息,有了这个peer之间就能直接传media数据了。peer通过ice组件向stun服务器协商后获得了candidate,所以这个信令服务器并不是ICE server,用google 文档上的话说,这个信令服务器可以是普通的socketserver,也可以sip/xmpp/Websocket服务器

mackmlink开机启动不了

Mac系统开机卡死无法完成启动的多种解决方法:1、启动或重新启动 Mac。2、听到启动声后,立即按住 Shift 键 (当然也开在启动声之前按住)。3、但出现apple 标志 + 进度条时 (也可稍微等待下,避免出现进入失败情况),松开shift 键。4、松开后,就是耐心等待。可能时间比平时正常进入系统时间有点长。5、这时进入登录界面,就会发现在屏幕右上角 就会出现 红色字体【安全模式】。6、输入用户名密码登录进来。然后再正常重启一道mac电脑 ,系统就能恢复正常使用了。解决方法2:1、打开 屏幕左上角 apple标志。2、选择关于本机 ,出现新的对话框。3、选择对话框中【概览】 -【系统报告】选项。 然后找到【软件】选项点击。这时会出现 启动模式。显示安全,也代表电脑进入安全模式。

linux pdc 是什么

可以!例如: /home/pdc/bin/aa start

PDC和LUERLING什么区别啊?

两个都是日本品牌,PDC价格高,LUERLING性价比高,都有旗舰店和天猫国际,线下覆盖也差不多,最大的区别可能就是一个原装进口,一个委托国内加工的吧,品质效果我认为差不多

smiley是形容词吗?那smily和smilingly呢?

smily释义:n.微笑;笑容v.微笑;露出笑容形容词: smiley副词: smilingly名词: smiler过去式: smiled过去分词: smiled现在分词: smiling第三人称单数: smiles

纸箱当中 kraft liner和test liner的区别

Testliner:全废纸挂面箱纸板 是挂面纸板的一个品种,大部分是利用回收纤维生产,有时挂一层牛皮浆。

Hygienic liner for fitting purposes是什么意思

Hygienic liner for fitting purposes的中文翻译Hygienic liner for fitting purposes 装修用卫生衬垫

苹果修复macOS 12.3.1 Monterey漏洞,但Big Sur/Catalina未修复

据 MacRumors 报道,近期苹果发布了 macOS Monterey 12.3.1,解决了两个可能在被主动利用的关键漏洞,但正如 Intego 本周指出的,苹果给 macOS Big Sur 和 macOS Catalina 用户留下了漏洞,还未修复。 macOS Monterey 12.3.1 更新修复了两个安全缺陷,包括一个 AppleAVD 问题,可能允许应用程序以内核权限执行任意代码,以及一个英特尔图形驱动问题,可能允许应用程序读取内核内存。苹果公司说,此前有报告说这些漏洞 “可能已被利用”,也就是有利用这些特定安全漏洞的攻击。 苹果经常在 macOS Monterey 更新的同时,为 macOS Catalina 和 macOS Big Sur 用户提供安全更新,以确保继续运行旧操作系统的 Mac 用户保持保护。在这种情况下,苹果这次 macOS 11 Big Sur 或 macOS 10.15 Catalina 没有安全修复。 macOS Big Sur 和 macOS Catalina 仍然需要支持,以便对漏洞进行修复,所以不清楚苹果为什么没有发布安全修复程序。据 Intego 称,这是苹果第一次没有在为 macOS Monterey 提供修复程序的同时为 Big Sur 和 Catalina 发布安全补丁。 根据 Intego 研究,Big Sur 仍然容易受到 CVE-2022-22675(AppleAVD 漏洞)的影响,而 CVE-2022-22674(英特尔图形驱动程序漏洞)可能同时影响 Big Sur 和 Catalina。 一些继续使用 Big Sur 或 Catalina 的 Mac 用户可以安装 Monterey 以获得安全修复,但其他 Mac 用户的硬件较旧,无法更新到 Monterey,这些用户没有办法解决现在公开的安全漏洞。 Intego 估计,目前使用中大约 35% 的 Mac 可能受到一个或两个漏洞的影响,而苹果公司还没有回应关于何时才能够为 Big Sur 和 Catalina 提供安全修复。

catalinna下一个是monterey吗

catalinna下一个是monterey。因为Macoscatalina是苹果公司在2019年6月4日推出的新版桌面操作系统,它就是macos发布的一次大版本更新,其代号为cataIina,它是美国加州的一座岛屿,新版macos以来命名。MacosMonterey是苹果公司研发的桌面端操作系统,于2021年6月8日在2o2l苹果全球开发者大会上发布。
 首页 上一页  2 3 4 5 6 7 8 9 10 11 12  下一页  尾页