考gre有什么用是rgre神工鬼斧opdg?

鬼斧神功的意思是?_百度知道
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。
该问题可能描述不清,建议你
鬼斧神功的意思是?
[guǐ fǔ shén gōng] 【解 释】形容事物之神奇巧妙,不是人力所能达到的( 指自然造就的)[本义有争议],也可以用来形容建筑、雕塑的 技艺精巧。非人工所能为。也说“神工鬼斧” 。(非自然)清屈大均《端州访研歌和诸公》:“年来巖底采无馀,鬼斧神工多得髓。”秦牧《艺海拾贝·酷肖》:“这个小故事我想不是无稽的,因为世间的确有许多‘功参造化’、‘鬼斧神工【解释】:像是鬼神制作出来的。形容艺术技巧高超,不是人力所能达到的。【出自】:《庄子·达生》:“梓庆削木为鐻,鐻成,见者惊忧鬼神。”【示例】:这种编织技术,给人以“浪漫主义手法”、“~”的印象。 ◎秦牧《巧匠和竹》【语法】:联合式;作主语、宾语;形容技艺非常精巧’的巧匠。”亦作“鬼斧工”。
采纳率:75%
来自团队:
形容建筑、雕塑的 技艺精巧,非人工所能为。也说“神工鬼斧 巧夺天工
本回答被提问者采纳
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包ilem教主治愈曲系列 - 歌单 - 网易云音乐
ilem教主治愈曲系列
ilem洗脑曲系列,新增歌曲一星期后按曲目排列,拯救强迫症,收藏一千加,阿里嘎多,本人工作党,更新随缘,有待添加的求评论私信提醒~
播放:177254次
喜欢这个歌单的人
网易云音乐多端下载
同步歌单,随时畅听320k好音乐
网易公司版权所有(C)杭州乐读科技有限公司运营:&p&并查集(Disjoint Set Union)&/p&&p&一行代码,极其简洁优美。&/p&&div class=&highlight&&&pre&&code class=&language-cpp&&&span class=&kt&&int&/span& &span class=&nf&&find&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&p&&(&/span&&span class=&n&&x&/span& &span class=&o&&==&/span& &span class=&n&&fa&/span&&span class=&p&&[&/span&&span class=&n&&x&/span&&span class=&p&&])&/span& &span class=&o&&?&/span& &span class=&nl&&x&/span& &span class=&p&&:&/span& &span class=&p&&(&/span&&span class=&n&&fa&/span&&span class=&p&&[&/span&&span class=&n&&x&/span&&span class=&p&&]&/span& &span class=&o&&=&/span& &span class=&n&&find&/span&&span class=&p&&(&/span&&span class=&n&&fa&/span&&span class=&p&&[&/span&&span class=&n&&x&/span&&span class=&p&&]));&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&时间复杂度也很优美。路径压缩和按秩合并的并查集的时间复杂度是 &img src=&///equation?tex=O%28%5Calpha%28n%29%29& alt=&O(\alpha(n))& eeimg=&1&& ,其中 &img src=&///equation?tex=%5Calpha& alt=&\alpha& eeimg=&1&& 是反Ackermann函数。(谢谢评论指出笔误。)近乎常数的时间复杂度。&/p&
并查集(Disjoint Set Union)一行代码,极其简洁优美。int find(int x) {
return (x == fa[x]) ? x : (fa[x] = find(fa[x]));
}时间复杂度也很优美。路径压缩和按秩合并的并查集的时间复杂度是 O(\alpha(n)) ,其中 \alpha 是反Ackermann函数。(谢谢评论…
&p&正巧,我也是对 Linux 的网络协议栈实现感兴趣[1]。&/p&&p&首先,我认为你最好先说明你的日常的开发环境,是 x86 还是 ARM,是 32-bit 还是 64-bit,是普通 server 还是嵌入式。如果你跟我一样在普通 x86-64 server 上写 Linux 程序,那么我有一个独特的内核学习方法:把相关内核代码编译成用户态程序,然后就像阅读调试普通单线程程序那样学习内核的相关实现。各种现成的静态/动态代码分析工具都能用上[2],单步跟踪也很方便,丢包、乱序等情况也容易复现。目前我在 &a href=&///?target=https%3A///chenshuo/linux-study& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&chenshuo/linux-study&i class=&icon-external&&&/i&&/a& 大体上把基本的 TCP 代码跑通了,然后写了几篇笔记:&/p&&ul&&li&&a href=&/p/& class=&internal&&Linux 中每个 TCP 连接最少占用多少内存?&/a&&/li&&li&&a href=&/p/& class=&internal&&Linux 4.4 之后 TCP 三路握手的新流程&/a&&/li&&li&&a href=&/p/& class=&internal&&Linux 4.5/4.6 中对 SO_REUSEPORT 的改进&/a&&/li&&/ul&&p&当然这个办法初始代价比较大,对于学习硬件平台无关的部分是比较适合的。以前也有人搞过,但是现在好像都没啥动静了。&/p&&ul&&li&Linux Kernel Library&/li&&li&NUSE: Network stack in USerspacE (LibOS)&/li&&li&User Mode Linux (这个还活着,但是似乎跟 GDB 不是很兼容。)&/li&&li&&a href=&///?target=https%3A///chenshuo/4.4BSD-Lite2& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&chenshuo/4.4BSD-Lite2&i class=&icon-external&&&/i&&/a& (这个是我搞的,方便《TCP/IP 详解 第2卷》的读者阅读理解源码)&/li&&/ul&&p&如果你对内核的其他部分感兴趣,可以用 QEMU + GDB 来单步跟踪内核代码运行。你可能需要用 busybox 做一个极简的 img,这样更容易关注你关心的逻辑。&/p&&p&&br&&/p&&p&[1] &a href=&/question//answer/& class=&internal&&陈硕:未来想从事Linux 后台开发,需要学习linux内核吗?像读内核源码。还是学好linux网络编程,C,算法。学习内核的意义有哪些呢?&/a&&/p&&p&[2] 我先是用这个办法把 BSD 4.4 的 TCP/IP 协议栈移植到了 Linux 用户态。链接:【&a href=&///?target=http%3A//blog.csdn.net/solstice/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&C1000k 新思路:用户态 TCP/IP 协议栈&i class=&icon-external&&&/i&&/a&】【&a href=&///?target=https%3A///chenshuo/4.4BSD-Lite2& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&chenshuo/4.4BSD-Lite2&i class=&icon-external&&&/i&&/a&】【&a href=&///?target=http%3A//tcpipv2.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&TCP/IP Illustrated vol. 2&i class=&icon-external&&&/i&&/a&】【三路握手的&a href=&///?target=http%3A//tcpipv2.org/en/latest/calltree/init.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Call Tree&i class=&icon-external&&&/i&&/a&】。&/p&
正巧,我也是对 Linux 的网络协议栈实现感兴趣[1]。首先,我认为你最好先说明你的日常的开发环境,是 x86 还是 ARM,是 32-bit 还是 64-bit,是普通 server 还是嵌入式。如果你跟我一样在普通 x86-64 server 上写 Linux 程序,那么我有一个独特的内核学习方…
通俗解释:&br&&b&PPP协议&/b&,&b&点对点协议&/b&,相当于你乘飞机的廊桥,把飞机和登机大厅物理连接起来,然后把旅客&b&(IP Packet)&/b&送到飞机&b&(Internet)&/b&上。&br&&br&&figure&&img data-rawwidth=&1024& data-rawheight=&683& src=&/a6a540acc8c378ae82a499_b.jpg& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&/a6a540acc8c378ae82a499_r.jpg&&&/figure&&br&&br&&br&而如果没有廊桥,需要摆渡车,&b&L2TP&/b&与&b&PPTP&/b&就相当于这个&b&摆渡车&/b&。&br&&br&&figure&&img data-rawwidth=&967& data-rawheight=&626& src=&/8a6ad8bec96_b.jpg& class=&origin_image zh-lightbox-thumb& width=&967& data-original=&/8a6ad8bec96_r.jpg&&&/figure&&br&&br&&br&&b&L2TP&/b&是一辆敞篷车,没有安全,为了全车旅客的安全,配备了安全人员&b&(IP security)&/b&,保护所有乘客&b&(IP Packet)&/b&,安全到达目的地,然后再登机&b&(Internet)。&/b&&br&&br&&figure&&img data-rawwidth=&639& data-rawheight=&452& src=&/4c2c130ab924d613ec4debe_b.jpg& class=&origin_image zh-lightbox-thumb& width=&639& data-original=&/4c2c130ab924d613ec4debe_r.jpg&&&/figure&&br&&br&&br&&br&&b&PPTP&/b&是两辆车,一辆负责开道(控制通道,TCP Port 1723,用于建立&b&安全通道&/b&),一辆运送旅客(IP/GRE)&b&安全通道&/b&,运送旅客的车配备了一些安全人员,只负责保卫VIP旅客&b&(IP Packet,end user traffic)&/b&的安全,其它旅客&b&(IP Packet,control traffic)&/b&就没有人保卫,最终也到达目的地,登机&b&(Internet)&/b&。&br&&br&&figure&&img data-rawwidth=&550& data-rawheight=&418& src=&/c910f277e66e730aee6a03d_b.jpg& class=&origin_image zh-lightbox-thumb& width=&550& data-original=&/c910f277e66e730aee6a03d_r.jpg&&&/figure&&br&&br&你可以看出,它们是殊途同归,最终的目的都是为了把旅客&b&(IP Packet)&/b&送上飞机&b&(Internet)&/b&,只是途径不一样,安全级别也不一样。&br&&br&&br&&br&&b&专业同学通道:&br&&br&PPTP:Point to Point Protocol Tunnel Protocol &/b&&br&&b&L2TP: Layer 2 Tunnel Protocol &/b&&br&&br&如果非要说他们有什么联系,那就是他们都能把PPP协议作为自己的Payload,封装PPP协议,这是他们之间唯一的联系,那有人一定要问,PPP作为点对点协议用在拨号网络好好的,为什么要把它封装起来?还要用什么PPTP,L2TP做啥?文章有点长,坚持看下去,你将会有不一样的收获。&br&&br&即然他们都和PPP协议有关,那我们一定要谈谈PPP,这是一种拨号上网协议,无论是传统电话网络PSTN、ISDN、还是ADSL,最终来完成用户认证,分配用户电脑/modem IP地址的都是由PPP协议来完成的,他们之间的差别只是传输介质不同,过程是殊途同归,就是在PPP client 和PPP server之间完成PPP会话,认证用户,分配IP地址。但是这三种传统的部署方式最大的不足:&b&太不灵活了!&/b&需要client 和server 之间是点对点连接,无论是PSTN circuit 、ISDN circuit、ADSL subscriber,都需要在同一台电信局端设备上,第一完成电路的终结( circuit termination),第二完成PPP会话的终结 ( PPP session termination),见下图:&br&&br&&br&&figure&&img data-rawwidth=&690& data-rawheight=&187& src=&/db8874b0cabe187ce7631eef_b.jpg& class=&origin_image zh-lightbox-thumb& width=&690& data-original=&/db8874b0cabe187ce7631eef_r.jpg&&&/figure&&br&&br&这就需要在PSTN 接入服务器(NAS)、ISDN NAS、DSLAM NAS上:&br&&br&&b&配置PPP 服务器&br&配置认证服务器&br&配置地址池&/b&&br&&br&这将会有很多很多的NAS存在于不同的网络,这种非常分散的方式不利于管理,而且管理成本很高。&br&&br&于是就有了一种设想,能否把&b&电路的终结&/b&与&b&PPP会话的终结&/b&这两个功能&b&物理分离&/b&,在一台设备上完成电路的终结,另一台设备完成PPP会话的终结。在这两台物理分离的设备上,以IP网络为传输介质,建立一个隧道tunnel, 来把电路终结剥离出来的PPP封装在这个隧道上,传输到PPP服务器,完成PPP会话的终结,这样我们只需要一台、二台集中的PPP服务器就可以了,见下图,值得庆幸的是,我们恰恰有这两种隧道协议可以完成这个设想。&br&&br&&figure&&img data-rawwidth=&690& data-rawheight=&262& src=&/ece1f9eb7df885533fbef42_b.jpg& class=&origin_image zh-lightbox-thumb& width=&690& data-original=&/ece1f9eb7df885533fbef42_r.jpg&&&/figure&&br&&br&这两种隧道协议就是PPTP和L2TP,虽然它们最终实现的目标一致,即封装PPP协议,穿越IP网络/ATM云/MPLS云,到达PPP Server,完成PPP会话,以及PPP用户数据流量,但是它们的实现方式大相径庭,所以我们还是分开介绍,先来谈谈PPTP协议。&br&&br&&b&PPTP&/b&&br&由微软公司牵头设计的企业标准,后来标准化,但是还是留下深深的企业烙印,对应标准RFC2637。&br&&br&分 control connection
和 tunnel connection 两个层次:&br&&br&Control connection是一种基于TCP的连接,用于协商如何建立、释放、修改tunnel,如何区别这些tunnel。&br&&br&PAC -----------TCP 1723-------------PNS&br&&br&Tunnel connection 是一种基于增强型GRE,跑在IP层上,协议号47,所谓增强型,是GRE头有Key Tunnel ID,一方面可以区分tunnel,另一方面可以无障碍穿越NAT设备。&br&&br&PAC -----------Enhanced GRE-------------PNS&br&&br&&br&&br&综上,无论是控制、数据层面都是跑在IP层以上的,所以PPTP离不开IP网络的支持。另外控制层面、数据层面的分离,多通道的模式使实现起来较复杂,配置防火墙策略也要同时考虑2个通道。&br&&br&&br&另外PPTP只是靠被封装的PPP协议来提供安全性,TCP会话以及GRE Tunnel都是明文方式,安全性强度不够高。&br&&br&&br&&b&L2TP&/b&&br&我们这里谈的是L2TPv2,即由思科公司牵头开发的协议,对应的标准是RFC2661。&br&&br&即然是由思科来牵头设计这个协议,那肯定要考虑网络的多样性,而不能像微软公司设计PPTP那样,仅仅考虑IP网络作为底层传输网络,所以L2TP可以传输在以下网络上:&br&&br&&b&1)IP网络&/b&&br&&br&协议号:115&br&&br&LAC -----------IP 115------------LNS&br&&br&优点是协议头较小,但不利于NAT Transversal &br&&br&&b&2)IP/UDP&/b&&br&&br&UDP PORT 1701&br&&br&LAC -----------UDP 1701-----------LNS&br&&br&方便NAT transversal&br&&br&&b&3)二层ATM交换网络&/b&&br&&br&LAC -----------ATM-----------LNS&br&&br&可以承载在ATM云上&br&&br&&b&4)MPLS&br&&/b&&br&LAC -----------MPLS-----------LNS&br&&br&可以承载在二层、三层MPLS VPN上&br&&br&&b&5)Frame Relay&/b&&br&&br&LAC -----------Frame Relay-----------LNS&br&&br&可以承载在帧中继交换网络上&br&&br&此外,控制层面、数据层面使用同一个通信通道,即用一个IP tunnel ,或同一个UDP tunnel ,简化网络的实现与部署。&br&&br&综合以上对网络多样性的支持、以及单通道的实现,使的L2TP获得更广泛的支持,所以L2TP获得了发展与升级,现在最新版是L2TPv3,不仅支持对PPP的封装,还支持Ethernet 、ATM、HDLC、Frame Relay 的封装,几乎可以和Layer 2 MPLS匹敌了,对应的协议标准RFC3931。&br&&br&但是L2TP本身也不提供安全加密,需要借助IP security来加密L2TP tunnel,因为是加密整个tunnel,所以安全性更高。&br&&br&以上PPTP,L2TP都是配置在接入网,其实这两个协议非常灵活,只要有IP网络的主机、服务器、路由器都可以使用,我们来谈谈PPTP、L2TP配置在用户电脑上的场景。&br&&br&用户希望PPTP、或者L2TP+ IP security 来远程拨号到公司服务器,获得公司VPN的连接。&br&这里有一个前提,就是用户已经ADSL上网了,有了IP connectivity ,这个时候这两种协议都可以实现,只要保证以下前提:&br&&br&&br&&b&a) PPTP&/b&&br&&br&防火墙开放 TCP 1723&br&防火墙开放 IP protocol 47,即GRE&br&NAT设备 支持enhanced GRE &br&&br&&b&b) L2TP&/b&&br&&br&采用UDP tunnel&br&防火墙开放 UDP 1701
L2TP&br&防火墙开放 UDP 500
IKE&br&防火墙开放 UDP 4500
IKE NAT Transversal&br&至于ESP,因为封装在UDP tunnel 里,所以没有必要单独考虑。
通俗解释: PPP协议,点对点协议,相当于你乘飞机的廊桥,把飞机和登机大厅物理连接起来,然后把旅客(IP Packet)送到飞机(Internet)上。 而如果没有廊桥,需要摆渡车,L2TP与PPTP就相当于这个摆渡车。 L2TP是一辆敞篷车,没有安全,为了全车旅客的安全…
给你说几个 inline 无法代替宏的地方:&br&&br&1. 循环展开:&br&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&c1&&// loop unroll double&/span&
&span class=&cp&&#define LOOP_UNROLL_DOUBLE(action, actionx2, width) do { \&/span&
&span class=&cp&&
unsigned long __width = (unsigned long)(width); \&/span&
&span class=&cp&&
unsigned long __increment = __width && 2; \&/span&
&span class=&cp&&
for (; __increment & 0; __increment--) { \&/span&
&span class=&cp&&
actionx2; \&/span&
&span class=&cp&&
actionx2; \&/span&
&span class=&cp&&
} \&/span&
&span class=&cp&&
switch (__width & 3) { \&/span&
&span class=&cp&&
case 2: actionx2; \&/span&
&span class=&cp&&
case 3: actionx2; \&/span&
&span class=&cp&&
case 1: \&/span&
&span class=&cp&&
} \&/span&
&span class=&cp&& } while (0)&/span&
&span class=&c1&&// loop unroll quatro&/span&
&span class=&cp&&#define LOOP_UNROLL_QUATRO(action, actionx2, actionx4, width) do { \&/span&
&span class=&cp&&
unsigned long __width = (unsigned long)(width); \&/span&
&span class=&cp&&
unsigned long __increment = __width && 2; \&/span&
&span class=&cp&&
for (; __increment & 0; __increment--) { \&/span&
&span class=&cp&&
actionx4; \&/span&
&span class=&cp&&
} \&/span&
&span class=&cp&&
switch (__width & 3) { \&/span&
&span class=&cp&&
case 2: actionx2; \&/span&
&span class=&cp&&
case 3: actionx2; \&/span&
&span class=&cp&&
case 1: \&/span&
&span class=&cp&&
} \&/span&
&span class=&cp&& } while (0)&/span&
&/code&&/pre&&/div&假设你需要高速循环做一个事情,那么展开循环可以极大的减少CPU分支,并且充分利用CPU流水线的并行效果,比如你开发一个 FIR滤波器来处理信号,那么你的代码如果从 for (...) { .... } 变成循环展开的话,可以这么写:&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&n&&LOOP_UNROLL_DOUBLE&/span&&span class=&p&&(&/span&
&span class=&p&&{&/span&
&span class=&n&&x&/span& &span class=&o&&=&/span& &span class=&o&&*&/span&&span class=&n&&src&/span&&span class=&o&&++&/span&&span class=&p&&;&/span&
&span class=&c1&&// do something with x and h and output to y&/span&
&span class=&o&&*&/span&&span class=&n&&dst&/span&&span class=&o&&++&/span& &span class=&o&&=&/span& &span class=&n&&y&/span&&span class=&p&&;&/span&
&span class=&p&&},&/span&
&span class=&p&&{&/span&
&span class=&n&&x1&/span& &span class=&o&&=&/span& &span class=&o&&*&/span&&span class=&n&&src&/span&&span class=&o&&++&/span&&span class=&p&&;&/span&
&span class=&n&&x2&/span& &span class=&o&&=&/span& &span class=&o&&*&/span&&span class=&n&&src&/span&&span class=&o&&++&/span&&span class=&p&&;&/span&
&span class=&c1&&// do something with x1 and h and output to y1&/span&
&span class=&c1&&// do something with x2 and h and output to y2&/span&
&span class=&o&&*&/span&&span class=&n&&dst&/span&&span class=&o&&++&/span& &span class=&o&&=&/span& &span class=&n&&y1&/span&&span class=&p&&;&/span&
&span class=&o&&*&/span&&span class=&n&&dst&/span&&span class=&o&&++&/span& &span class=&o&&=&/span& &span class=&n&&y2&/span&&span class=&p&&;&/span&
&span class=&p&&},&/span&
&span class=&n&&nsamples&/span&&span class=&p&&,&/span&
&span class=&p&&);&/span&
&/code&&/pre&&/div&如此写法将每个循环只计算一个 sample,变为每个循环同时计算两个sample,分开写代码,也能更好的利用 SIMD去加速同时多个 sample的计算过程,这就是利用循环展开来优化性能的用法,直接传 &{...}& 里面的运行代码给宏,宏不变,但是每处使用LOOP_UNROLL的地方 &{.. } & 中的代码都是不同的,inline是代替不了的,你总不至于传个函数指针过去吧,这时性能优化方面情况。&br&&br&2. 函数组装:&br&&br&想象一下,你写图形图像的代码,现在你需要给像素合成实现 SRC_ATOP, SRC_OVER, SRC_IN, SRC_OUT, DST_ATOP, DST_OVER, DST_IN, DST_OUT, XOR, PLUS, ALLANON, TINT, DIFF, DARKEN, LIGHTEN, SCREEN, OVERLAY 等等 二十种像素合成的方法,你如果不用宏,那么你需要写多少个函数?20多个看起来类似的函数,你不得写疯了么?此时用函数指针其实是很浪费性能的事情,那么该如何写呢?你可以规定一系列用来计算composite的方法,接受两组 RGBA,生成新的,比如:&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&cm&&/* compositing */&/span&
&span class=&cp&&#define IBLEND_COMPOSITE(sr, sg, sb, sa, dr, dg, db, da, FS, FD) do { \&/span&
&span class=&cp&&
(dr) = _ipixel_mullut[(FS)][(sr)] + _ipixel_mullut[(FD)][(dr)]; \&/span&
&span class=&cp&&
(dg) = _ipixel_mullut[(FS)][(sg)] + _ipixel_mullut[(FD)][(dg)]; \&/span&
&span class=&cp&&
(db) = _ipixel_mullut[(FS)][(sb)] + _ipixel_mullut[(FD)][(db)]; \&/span&
&span class=&cp&&
(da) = _ipixel_mullut[(FS)][(sa)] + _ipixel_mullut[(FD)][(da)]; \&/span&
&span class=&cp&& } while (0)&/span&
&span class=&cm&&/* premultiply: src over */&/span&
&span class=&cp&&#define IBLEND_OP_SRC_OVER(sr, sg, sb, sa, dr, dg, db, da) do { \&/span&
&span class=&cp&&
IUINT32 FD = 255 - (sa); \&/span&
&span class=&cp&&
IBLEND_COMPOSITE(sr, sg, sb, sa, dr, dg, db, da, 255, FD); \&/span&
&span class=&cp&& } while (0)&/span&
&span class=&cm&&/* premultiply: dst atop */&/span&
&span class=&cp&&#define IBLEND_OP_DST_ATOP(sr, sg, sb, sa, dr, dg, db, da) do { \&/span&
&span class=&cp&&
IUINT32 FS = 255 - (da); \&/span&
&span class=&cp&&
IUINT32 FD = (sa); \&/span&
&span class=&cp&&
IBLEND_COMPOSITE(sr, sg, sb, sa, dr, dg, db, da, FS, FD); \&/span&
&span class=&cp&& } while (0)&/span&
&span class=&cm&&/* premultiply: dst in */&/span&
&span class=&cp&&#define IBLEND_OP_DST_IN(sr, sg, sb, sa, dr, dg, db, da) do { \&/span&
&span class=&cp&&
IUINT32 FD = (sa); \&/span&
&span class=&cp&&
IBLEND_COMPOSITE(sr, sg, sb, sa, dr, dg, db, da, 0, FD); \&/span&
&span class=&cp&& } while (0)&/span&
&/code&&/pre&&/div&然后用 #连接各种方法和格式,生成不同的函数,比如:&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&cp&&#define IPIXEL_COMPOSITE_FN(name, opname) \&/span&
&span class=&cp&&static void ipixel_comp_##name(IUINT32 *dst, const IUINT32 *src, int w)\&/span&
&span class=&cp&&{ \&/span&
&span class=&cp&& IUINT32 sr, sg, sb, sa, dr, dg, db, \&/span&
&span class=&cp&& for (; w & 0; dst++, src++, w--) { \&/span&
&span class=&cp&&
_ipixel_load_card(src, sr, sg, sb, sa); \&/span&
&span class=&cp&&
_ipixel_load_card(dst, dr, dg, db, da); \&/span&
&span class=&cp&&
IBLEND_OP_##opname(sr, sg, sb, sa, dr, dg, db, da); \&/span&
&span class=&cp&&
dst[0] = IRGBA_TO_A8R8G8B8(dr, dg, db, da); \&/span&
&span class=&cp&& } \&/span&
&span class=&cp&&}&/span&
&/code&&/pre&&/div&然后开始生成我们的各种合成函数:&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_xor&/span&&span class=&p&&,&/span& &span class=&n&&XOR&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_plus&/span&&span class=&p&&,&/span& &span class=&n&&PLUS&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_src_atop&/span&&span class=&p&&,&/span& &span class=&n&&SRC_ATOP&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_src_in&/span&&span class=&p&&,&/span& &span class=&n&&SRC_IN&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_src_out&/span&&span class=&p&&,&/span& &span class=&n&&SRC_OUT&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_src_over&/span&&span class=&p&&,&/span& &span class=&n&&SRC_OVER&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_dst_atop&/span&&span class=&p&&,&/span& &span class=&n&&DST_ATOP&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_dst_in&/span&&span class=&p&&,&/span& &span class=&n&&DST_IN&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_dst_out&/span&&span class=&p&&,&/span& &span class=&n&&DST_OUT&/span&&span class=&p&&);&/span&
&span class=&n&&IPIXEL_COMPOSITE_PREMUL&/span&&span class=&p&&(&/span&&span class=&n&&pre_dst_over&/span&&span class=&p&&,&/span& &span class=&n&&DST_OVER&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&这样你相当于定义了:&br&&div class=&highlight&&&pre&&code class=&language-text&&ipixel_comp_pre_xor (...)
ipixel_comp_pre_plus (...)
ipixel_comp_dst_over (...)
&/code&&/pre&&/div&等好几个函数了,并且这些函数都是被你 “组装” 出来的,你并没有使用函数指针,也没有笨重的去写20多个函数。进一步如果你写图形图像你会发现你需要面对多种设备的像素格式,从 A8R8G8B8, A8B8G8R8 到 A1R5G5B5 , 主流需要处理的像素格式都有10多种。&br&&br&那么你可以把 “从不同格式读取 r,g,b,a”, 以及 “将 r,g,b,a组装成任意格式”,展开成很多个宏,然后不管你在这些像素格式里面做转换还是要做一些其他处理,你都可以用任意的 “像素读写” 宏 + “像素计算” 宏 组装成一个个具体需要的函数。&br&&br&所以用宏来解决性能问题,并且简化自己的程序设计往往能起到 inline不能起的作用,甚至能完成很多 template 所不能完成的任务。&br&&br&3. 数据结构和算法:&br&&br&具体可以参考 Linux Kernel的 include/linux/list.h:&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&k&&struct&/span& &span class=&n&&list_head&/span& &span class=&p&&{&/span&
&span class=&k&&struct&/span& &span class=&n&&list_head&/span& &span class=&o&&*&/span&&span class=&n&&next&/span&&span class=&p&&,&/span& &span class=&o&&*&/span&&span class=&n&&prev&/span&&span class=&p&&;&/span&
&span class=&p&&};&/span&
&span class=&cp&&#define INIT_LIST_HEAD(ptr) do { \&/span&
&span class=&cp&& (ptr)-&next = (ptr); (ptr)-&prev = (ptr); \&/span&
&span class=&cp&&} while (0)&/span&
&span class=&cm&&/*&/span&
&span class=&cm&& * Insert a new entry between two known consecutive entries. &/span&
&span class=&cm&& *&/span&
&span class=&cm&& * This is only for internal list manipulation where we know&/span&
&span class=&cm&& * the prev/next entries already!&/span&
&span class=&cm&& */&/span&
&span class=&k&&static&/span& &span class=&n&&__inline__&/span& &span class=&kt&&void&/span& &span class=&nf&&__list_add&/span&&span class=&p&&(&/span&&span class=&k&&struct&/span& &span class=&n&&list_head&/span& &span class=&o&&*&/span& &span class=&n&&new&/span&&span class=&p&&,&/span&
&span class=&k&&struct&/span& &span class=&n&&list_head&/span& &span class=&o&&*&/span& &span class=&n&&prev&/span&&span class=&p&&,&/span&
&span class=&k&&struct&/span& &span class=&n&&list_head&/span& &span class=&o&&*&/span& &span class=&n&&next&/span&&span class=&p&&)&/span&
&span class=&p&&{&/span&
&span class=&n&&next&/span&&span class=&o&&-&&/span&&span class=&n&&prev&/span& &span class=&o&&=&/span& &span class=&n&&new&/span&&span class=&p&&;&/span&
&span class=&n&&new&/span&&span class=&o&&-&&/span&&span class=&n&&next&/span& &span class=&o&&=&/span& &span class=&n&&next&/span&&span class=&p&&;&/span&
&span class=&n&&new&/span&&span class=&o&&-&&/span&&span class=&n&&prev&/span& &span class=&o&&=&/span& &span class=&n&&prev&/span&&span class=&p&&;&/span&
&span class=&n&&prev&/span&&span class=&o&&-&&/span&&span class=&n&&next&/span& &span class=&o&&=&/span& &span class=&n&&new&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&这里定义了一个 LIST,kernel中,能用 inline的地方都用了,但是有些地方用不了,比如,你有一个结构体 (netfilter 部分):&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&k&&struct&/span& &span class=&n&&nf_hook_ops&/span&
&span class=&p&&{&/span&
&span class=&k&&struct&/span& &span class=&n&&list_head&/span& &span class=&n&&list&/span&&span class=&p&&;&/span&
&span class=&cm&&/* User fills in from here down. */&/span&
&span class=&n&&nf_hookfn&/span& &span class=&o&&*&/span&&span class=&n&&hook&/span&&span class=&p&&;&/span&
&span class=&kt&&int&/span& &span class=&n&&pf&/span&&span class=&p&&;&/span&
&span class=&kt&&int&/span& &span class=&n&&hooknum&/span&&span class=&p&&;&/span&
&span class=&cm&&/* Hooks are ordered in ascending priority. */&/span&
&span class=&kt&&int&/span& &span class=&n&&priority&/span&&span class=&p&&;&/span&
&span class=&p&&};&/span&
&/code&&/pre&&/div&然后你有一个链表,记录着很多 nf_hook_ops,你取到了其中一个节点的指针,其实是指向结构体的 &list这个成员的,你需要得到对应结构体的指针,那么你可以用下面的 list 的宏:&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&cm&&/**&/span&
&span class=&cm&& * list_entry - get the struct for this entry&/span&
&span class=&cm&& * @ptr: the &struct list_head pointer.&/span&
&span class=&cm&& * @type: the type of the struct this is embedded in.&/span&
&span class=&cm&& * @member: the name of the list_struct within the struct.&/span&
&span class=&cm&& */&/span&
&span class=&cp&&#define list_entry(ptr, type, member) \&/span&
&span class=&cp&& ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)-&member)))&/span&
&/code&&/pre&&/div&比如,list_entry(ptr, struct nf_hook_ops, list) 就能根据节点指针,和在某个 struct里面的位置,取到某个节点对应的 struct的指针了。这个做法,用 inline也是没法做的。&br&&br&同样的应用,在 Kernel中,还有红黑树 rbtree.h,rbtree.c中的实现,和 list很类似,大量的宏应用。Linux 用基础的宏实现的 list, rbtree等基础数据结构,用起来是相当方便的,有些地方比 std::list, std::map 都方便多了,比 STL性能高的同时,避免象模版一样为每种类型生成不同的代码,让你的二进制程序变得很臃肿。&br&&br&比如你在做题的时候,用上了这样的数据结构,你程序会比用 stl容器的代码更高效和精简,同时你不知道目标平台 STL是怎么实现的,你无法控制,明明我在这个平台写着很快的代码,为何换个平台又慢了,为了追求究极性能,这样重新定义数据结构,其实是可以理解的。&br&&br&4. 其他 inline 无法代替宏的地方&br&&ul&&li&针对不同平台特性(比如整数是32还是64,lsb还是msb)写出的优化代码。&br&&/li&&li&泛型的模拟&br&&/li&&li&小型高频重复的代码片&br&&/li&&li&硬件操作的定义&/li&&/ul&等等,很多情况,inline或者 template还是无法把宏给代替了,所以很多开源项目的代码里面,大量的出现各种宏,主要是出于这些方面的考虑。&br&&br&-----------
给你说几个 inline 无法代替宏的地方: 1. 循环展开: // loop unroll double
#define LOOP_UNROLL_DOUBLE(action, actionx2, width) do { \
unsigned long __width = (unsigned long)(width); \
unsigned long __increment = __width && 2; \
&figure&&img src=&/50/v2-908ef15ae3a6bcc8179eda602c6c06c0_b.jpg& data-rawwidth=&1000& data-rawheight=&480& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&/50/v2-908ef15ae3a6bcc8179eda602c6c06c0_r.jpg&&&/figure&&blockquote&&p&&em&在深度学习项目开始前,选择一个合适的框架是非常重要的事情。最近,来自数据科学公司 Silicon Valley Data Science 的数据工程师 Matt Rubashkin(UC Berkeley 博士)为我们带来了深度学习 7 种流行框架的深度横向对比,希望本文能对你带来帮助。&/em&&br&&/p&&/blockquote&&figure&&img src=&/50/v2-ed63836f74bee1d0e11d6a9536ddad0f_b.jpg& data-rawheight=&788& data-rawwidth=&3600& class=&origin_image zh-lightbox-thumb& width=&3600& data-original=&/50/v2-ed63836f74bee1d0e11d6a9536ddad0f_r.jpg&&&/figure&&p&在 SVDS,我们的研发团队一直在研究不同的深度学习技术;从识别图像到语音,我们也在各类框架下实现了不少应用。在这个过程中,我们意识到需要一个简明的方式来获取数据、创建模型、同时评估这些模型的表现。但当我们一次次开始新的深度学习项目时,我们却一直没有找到一个可以参考的标准来告诉自己如何开始。&br&&/p&&p&现在,为了回馈开源社区,同时帮助后来者,我们决定以我们的经验对目前流行的几种工具(Theano、TensorFlow、Torch、Caffe、MXNet、Neon 和 CNTK)进行一次横向对比。以下图表展示了各类深度学习工具的优劣,希望对大家能有所帮助。&br&&/p&&p&先放结论:&/p&&figure&&img src=&/50/v2-67c36f046eb38d4a130fbf68f7611368_b.png& data-rawheight=&563& data-rawwidth=&1024& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&/50/v2-67c36f046eb38d4a130fbf68f7611368_r.png&&&/figure&&p&这组对比参考了多种公开基准评测,以及我们在图像/语音识别应用时对这些技术的主观印象。此外,你需要注意:&br&&/p&&p&&strong&语言&/strong&&br&&/p&&p&当你开始一个深度学习项目时,你最好使用一个支持你所会语言的框架。比如 Caffe(C++)和 Torch(Lua)只能支持有限的语言(最近,随着 &a href=&/p/& class=&internal&&PyTorch 的出现&/a&,情况有所改观)。所以如果你希望选用上述两个框架,我们建议你事先熟悉 C++或 Lua 语言。相比之下,TensorFlow 与 MXNet 具有丰富的多语言支持,即使你对 C++感到陌生也可以使用它们。&/p&&p&&figure&&img src=&/50/v2-018adbbbdf58d7e8ff59acb3a0a4b8ea_b.png& data-rawheight=&831& data-rawwidth=&752& class=&origin_image zh-lightbox-thumb& width=&752& data-original=&/50/v2-018adbbbdf58d7e8ff59acb3a0a4b8ea_r.png&&&/figure&&figure&&img src=&/50/v2-1f22b8c280a111cceee9482_b.png& data-rawheight=&821& data-rawwidth=&752& class=&origin_image zh-lightbox-thumb& width=&752& data-original=&/50/v2-1f22b8c280a111cceee9482_r.png&&&/figure&&strong&教程和资源&/strong&&br&&/p&&p&目前,各类深度学习框架的教程与可利用的资源在质量和数量上有着显著的不同。Theano,TensorFlow,Torch 和 MXNet 有着很详尽的文档教程,很容易被初学者理解和实现。与此相比,虽然微软的 CNTK 和英特尔的 Nervana Neon 也是强大的工具,我们却很少能见到有关它们的新手级资料。此外,在研究过程中,我们发现 GitHub 社区的参与度不仅可以用于准确地评价不同工具的开发水平,而且还是在搜索 StackOverflow 或 repo 的 Git Issues 时能否快速解决问题的参考性指标。当然,作为谷歌提供的框架,TensorFlow 理所当然地在教程,资源,开发者和社区贡献者的数量上遥遥领先。&/p&&p&&figure&&img src=&/50/v2-9a4f2a6d78da0e34b5c27b0282b7ade5_b.png& data-rawheight=&821& data-rawwidth=&752& class=&origin_image zh-lightbox-thumb& width=&752& data-original=&/50/v2-9a4f2a6d78da0e34b5c27b0282b7ade5_r.png&&&/figure&&strong&CNN 建模能力&/strong&&br&&/p&&p&卷积神经网络(CNN)经常被用于图像识别、推荐引擎和自然语言识别等方向的应用。CNN 由一组多层的神经网络组成,在运行时会将输入的数据进行预定义分类的评分。CNN 也可用于回归分析,例如构成自动驾驶汽车中有关转向角的模型。在横评中,我们评价一种框架的 CNN 建模能力考虑到以下几个特性:定义模型的机会空间、预构建层的可用性、以及可用于连接这些层的工具和功能。我们发现,Theano,Caffe 和 MXNet 都有很好的 CNN 建模能力。其中,TensorFlow 因为易于建立的 Inception V3 模型,Torch 因为其丰富的 CNN 资源——包括易于使用的时间卷积集使得这两种框架在 CNN 建模能力上脱颖而出。&br&&/p&&p&&strong&RNN 建模能力&/strong&&br&&/p&&p&循环神经网络(RNN)常用于语音识别,时间序列预测,图像字幕和其他需要处理顺序信息的任务。由于预建的 RNN 模型不如 CNN 数量多,因此,如果你已经有一个 RNN 深度学习项目,优先考虑旧 RNN 模型是在哪种框架里实现的最重要。目前,Caffe 上的 RNN 资源最少,而 Microsoft 的 CNTK 和 Torch 有丰富的 RNN 教程和预构建模型。当然,最流行的 TensorFlow 中也有一些 RNN 资源,TFLearn 和 Keras 中更有很多使用 TensorFlow 的 RNN 示例。&br&&/p&&p&&strong&架构&/strong&&br&&/p&&p&为在特定框架中构建和训练新模型,易于使用和模块化的前端是至关重要的。TensorFlow,Torch 和 MXNet 都有直观而模块化的架构,让开发相对变得简单。相比之下,我们在 Caffe 这样的框架上需要进行大量的工作才能创建一个新层。另外我们发现在开发过程中,因为有 TensorBoard web GUI 等应用的存在,TensorFlow 极易在训练中和训练后进行 debug 和监控。&br&&/p&&p&&strong&速度&/strong&&br&&/p&&p&Torch 和 Nervana 具有开源卷积神经网络基准测试的最佳性能:&/p&&p&&a href=&/?target=https%3A///soumith/convnet-benchmarks/blob/master/README.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&convnet-benchmarks/README.md at master · soumith/convnet-benchmarks · GitHub&i class=&icon-external&&&/i&&/a&&br&&/p&&p&TensorFlow 的性能在大多数测试中是具有竞争力的,而 Caffe 和 Theano 稍稍落后:&/p&&p&&a href=&/?target=https%3A///tobigithub/tensorflow-deep-learning/wiki/tf-benchmarks& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&tf benchmarks · tobigithub/tensorflow-deep-learning Wiki · GitHub&i class=&icon-external&&&/i&&/a&&br&&/p&&p&微软声称他们的 CNTK 在一些 RNN 训练任务中有最快的速度。&br&&/p&&p&在另一项对比 Theano、Torch 和 TensorFlow 的 RNN 性能的研究中,Theano 是其中最快的:&/p&&p&&a href=&/?target=https%3A//arxiv.org/abs/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&[] Comparative Study of Deep Learning Software Frameworks&i class=&icon-external&&&/i&&/a&&br&&/p&&p&&strong&多 GPU 支持&/strong&&br&&/p&&p&大多数深度学习应用都需要用到巨量的浮点运算(FLOP)。例如,百度的 DeepSpeech 识别模型需要 10s ExaFLOPs 用于训练,这是大于 10e18 的计算量:&/p&&p&&a href=&/?target=https%3A//arxiv.org/abs/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&End-to-End Speech Recognition in English and Mandarin&i class=&icon-external&&&/i&&/a&&br&&/p&&p&考虑到目前英伟达 Pascal 架构的 TitanX 等顶级显卡可以每秒执行 10e9 FLOP:&/p&&p&&a href=&/?target=https%3A///en-us/geforce/products/10series/titan-x-pascal/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&TITAN X Graphics Card with Pascal from NVIDIA GeForce&i class=&icon-external&&&/i&&/a&&br&&/p&&p&因此,假如需要在大型数据集上训练一个新模型——用单 GPU 机器的话——可能会需要一个星期之久。为了减少构建模型所需的时间,我们需要使用多 GPU 并联的方式组建自己的机器。幸运的是,上述大部分架构都可以很好地支持多 GPU 运算。其中,据报道 MXNet 有着最好的多 GPU 优化引擎:&/p&&p&&a href=&/?target=http%3A///2016/11/mxnet-default-framework-deep-learning-aws.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&&/span&&span class=&invisible&&/2016/11/mxnet-default-framework-deep-learning-aws.html&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&br&&/p&&p&&strong&Keras 兼容性&/strong&&br&&/p&&p&Keras 是一个用于快速构建深度学习原型的高级库。我们在实践中发现,它是数据科学家应用深度学习的好帮手。Keras 目前支持两种后端框架:TensorFlow 与 Theano,而且 Keras 再过不久就会成为 TensorFlow 的默认 API:&/p&&p&&a href=&/?target=http%3A//www.fast.ai//keras/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Big deep learning news: Google Tensorflow chooses Keras&i class=&icon-external&&&/i&&/a&&br&&/p&&p&尽管如此,Keras 的作者表示,这一高级库在未来仍会作为支持多种框架的前端存在:&/p&&p&&a href=&/?target=https%3A///fchollet/keras/issues/5050%23issuecomment-& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Good news, Tensorflow chooses Keras! · Issue #5050 · fchollet/keras · GitHub&i class=&icon-external&&&/i&&/a&&br&&/p&&p&&strong&总结&/strong&&br&&/p&&p&如果你想要开始深度学习,你应该从评估自己的团队技能和业务需求开始。例如,如果一个以 Python 为中心的团队想开发图像识别的应用程序,你应该使用 TensorFlow,因为它有丰富的资源,较好性能和完整的原型工具。如果一个有 Lua 能力的团队希望将 RNN 大规模应用到生产环境中去,他们则会受益于 Torch 的高速和强大的 RNN 建模能力。&br&&/p&&p&未来,我们将继续讨论在更大规模的应用中这些框架的表现。这些挑战包括多机并联时的多 GPU 优化,多种开源库的兼容性,如 CMU Sphinx 和 Kaldi 等,尽请期待。&/p&&br&&p&选自&a href=&/?target=http%3A///getting-started-deep-learning/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SVDS&i class=&icon-external&&&/i&&/a&&b&机器之心编译&/b&&/p&
在深度学习项目开始前,选择一个合适的框架是非常重要的事情。最近,来自数据科学公司 Silicon Valley Data Science 的数据工程师 Matt Rubashkin(UC Berkeley 博士)为我们带来了深度学习 7 种流行框架的深度横向对比,希望本文能对你带来帮助。 在 SVDS…
&p&==介绍==&/p&&p&ftrace的跟踪方法是一种总体跟踪法,换句话说,你统计了一个事件到下一个事件所有的时间长度,然后把它们放到时间轴上,你可以知道整个系统运行在时间轴上的分布。&/p&&p&这种方法很准确,但跟踪成本很高。所以,我们也需要一种抽样形态的跟踪方法。perf提供的就是这样的跟踪方法。&/p&&p&perf的原理是这样的:每隔一个固定的时间,就在CPU上(每个核上都有)产生一个中断,在中断上看看,当前是哪个pid,哪个函数,然后给对应的pid和函数加一个统计值,这样,我们就知道CPU有百分几的时间在某个pid,或者某个函数上了。这个原理图示如下: &/p&&p&&figure&&img data-rawheight=&200& data-rawwidth=&987& src=&/50/9a1cce72e02b748c02d182d56dc5df40_b.png& class=&origin_image zh-lightbox-thumb& width=&987& data-original=&/50/9a1cce72e02b748c02d182d56dc5df40_r.png&&&/figure& 很明显可以看出,这是一种采样的模式,我们预期,运行时间越多的函数,被时钟中断击中的机会越大,从而推测,那个函数(或者pid等)的CPU占用率就越高。&/p&&p&这种方式可以推广到各种事件,比如上一个博文我们介绍的ftrace的事件,你也可以在这个事件发生的时候上来冒个头,看看击中了谁,然后算出分布,我们就知道谁会引发特别多的那个事件了。&/p&&p&当然,如果某个进程运气特别好,它每次都刚好躲过你发起探测的位置,你的统计结果可能就完全是错的了。这是所有采样统计都有可能遇到的问题了。 &br&&/p&&p&还是用我们介绍ftrace时用到的那个sched_switch为例,我们可以用tracepoint作为探测点,每次内核调用这个函数的时候,就上来看看,到底谁引发了这个跟踪点(这个只能用来按pid分类,按函数分类没有用,因为tracepoint的位置是固定的),比如这样:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e sched:sched_switch -s pid
&/code&&/pre&&/div&&figure&&img data-rawheight=&600& data-rawwidth=&754& src=&/50/a3d60ec6cceb2ac81433c9_b.png& class=&origin_image zh-lightbox-thumb& width=&754& data-original=&/50/a3d60ec6cceb2ac81433c9_r.png&&&/figure&&p&当然,perf使用更多是CPU的PMU计数器,PMU计数器是大部分CPU都有的功能,它们可以用来统计比如L1 Cache失效的次数,分支预测失败的次数等。PMU可以在这些计数器的计数超过一个特定的值的时候产生一个中断,这个中断,我们可以用和时钟一样的方法,来抽样判断系统中哪个函数发生了最多的Cache失效,分支预测失效等。&/p&&p&下面是一个分支预测失效的跟踪命令和动态结果:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e branch-misses
&/code&&/pre&&/div&&p&&figure&&img data-rawheight=&614& data-rawwidth=&809& src=&/50/29a16c30ba1de309b967ccc_b.png& class=&origin_image zh-lightbox-thumb& width=&809& data-original=&/50/29a16c30ba1de309b967ccc_r.png&&&/figure&我们从这里就可以看到系统中哪些函数制造了最多的分支预测失败,我们可能就需要在那些函数中考虑一下有没有可能塞进去几个likely()/unlikely()这样的宏了。 &br&&/p&&p&而且读者应该也注意到了,perf比起ftrace来说,最大的好处是它可以直接跟踪到整个系统的所有程序(而不仅仅是内核),所以perf通常是我们分析的第一步,我们先看到整个系统的outline,然后才会进去看具体的调度,时延等问题。而且perf本身也告诉你调度是否正常了,比如内核调度子系统的函数占用率特别高,我们可能就知道我们需要分析一下调度过程了。&/p&&p&==使用perf==&/p&&p&perf的源代码就是Linux的源代码目录中,因为它在相当程度上和内核是关联的。它会使用Linux内核的头文件。但你编译内核的时候并不会编译它,你必须主动进入tools/perf目录下面,执行make才行。&/p&&p&perf支持很多功能,make的时候它会自动检查这些功能是否存在。比如前面我们用了tracepoint进行事件收集,你就要保证你的系统中有libtracepoint这个库。perf的自由度设计得相当高,很多功能你都可以没有,并不会影响你的基本功能。&/p&&p&由于perf和内核关联,所以理论上,你用哪个内核,就应该使用对应内核的perf,这能保证接口的一致。所以很多类似Ubuntu这样的发行版,你装哪个内核,就要装对应内核的perf命令,而通过的perf命令入其实只是个脚本,根据你当前的perf命令,调用不同perf版本。&/p&&p&但那只是理论上,实践中,其实perf的用户-内核接口相当稳定,很多时候跨版本使用是没有问题的,由于perf的版本还在高速发展中,而且很多发行版的perf版本没有使能很多功能,我在实践中经常直接找最新的内核自己重新编译版本,好像也没有出过什么问题。读者可以有限度参考这个经验。perf也没有很多的路径依赖,你编译完以后连安装都不用,直接用绝对路径调用你编译的版本即可。 &br&&/p&&br&&p&==一般跟踪==&/p&&p&前面我们已经看了几个perf工作的例子了。类似git,docker等多功能工具,perf也是使用perf &子命令&这种模式。所有人首先需要学习的是两个最简单的命令:perf list和perf top。&/p&&p&perf list列出perf可以支持的所有事件。例如这样:&/p&&p&&figure&&img data-rawheight=&582& data-rawwidth=&877& src=&/50/8f1b67292_b.png& class=&origin_image zh-lightbox-thumb& width=&877& data-original=&/50/8f1b67292_r.png&&&/figure&旧版本还会列出所有的tracepoint,但那个列表太长了,新版本已经不列这个东西了,读者可以直接到ftrace那边去看就好了。&/p&&p&perf top可以动态收集和更新统计列表,和很多其他perf命令一样。它支持很多参数,但我们关键要记住两个参数:&/p&&p&1. -e 指定跟踪的事件&/p&&p&-e可以指定前面perf list提供的所有事件(包括没有列出的tracepoint),可以用多个-e指定多个事件同时跟踪(但显示的时候会分开显示)&/p&&p&一个-e也可以直接指定多个事件,中间用逗号隔开即可:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo perf top -e branch-misses,cycles
&/code&&/pre&&/div&&p& 事件可以指定后缀,比如我想只跟踪发生在用户态时产生的分支预测失败,我可以这样:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e branch-misses:u,cycles
&/code&&/pre&&/div&&p& 全部事件都有这个要求,我还可以:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e ‘{branch-misses,cycles}:u'
&/code&&/pre&&/div&&p&看看perf-list的手册,会找到更多的后缀,后缀我也用得比较少,读者对这个有兴趣,可以自己深入挖掘一下,如果有什么好的使用经验,希望也可以告诉我。&br&&/p&&br&&p&2. -s 指定按什么参数来进行分类 &/p&&p&-s参数可以不使用,默认会按函数进行分类,但如果你想按pid来分,就需要靠-s来进行分类了。前面我们已经看过这样的例子了。-s也可以指定多个域(用逗号隔开),例如这样:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e 'cycles' -s comm,pid,dso
&/code&&/pre&&/div&&figure&&img data-rawheight=&369& data-rawwidth=&768& src=&/50/c47ea36e6a78cd96ec047c1605cac3e6_b.png& class=&origin_image zh-lightbox-thumb& width=&768& data-original=&/50/c47ea36e6a78cd96ec047c1605cac3e6_r.png&&&/figure&&p&perf-top用来理解,体会perf的功能是比较好的,但实践中用得不多,用得比较多的是perf-record和perf-report命令。perf-record用来启动一次跟踪,而perf-report用来输出跟踪结果。&/p&&p&一般的过程是:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf record -e 'cycles' -- myapplication arg1 arg2
sudo perf report
&/code&&/pre&&/div&&p&下面是一个报告的例子:&/p&&p&&figure&&img data-rawheight=&416& data-rawwidth=&811& src=&/50/b9392cada1d_b.png& class=&origin_image zh-lightbox-thumb& width=&811& data-original=&/50/b9392cada1d_r.png&&&/figure&perf record在当前目录产生一个perf.data文件(如果这个文件已经存在,旧的文件会被改名为perf.data.old),用来记录过程数据。之后运行的perf report命令会输出统计的结果。perf.data只包含原始数据,perf report需要访问本地的符号表,pid和进城的对应关系等信息来生成报告。所以perf.data不能直接拷贝到其他机器上用的。但你可以通过perf-archive命令把所有这些数据打包,这样移到另一个机器上就可以用了。&/p&&p&请注意,perf-archive是指perf-archive这个命令,不是指perf archive这个子命令。这个命令在编译perf源代码的时候会产生的,如果你的发行版不支持,可以自己编译一个。比较可惜的是,perf-archive备份的代码不能跨平台使用(比如你从arm平台上备份的数据,在x86上是分析不了的)。&br&&/p&&p&perf.data保留前一个版本,可以支持perf diff这个命令,这个命令比较两次两次运行的区别。这样你可以用不同参数运行你的程序,看看运行结果有什么不同,用前面这个cs程序为例,我用4线程对比2线程,就有如下结果:&figure&&img data-rawheight=&457& data-rawwidth=&851& src=&/50/1fa34c856fead98cd9f1e3bbc57c8e29_b.png& class=&origin_image zh-lightbox-thumb& width=&851& data-original=&/50/1fa34c856fead98cd9f1e3bbc57c8e29_r.png&&&/figure&我们这里看到,增加线程后,heavy_cal的占比大幅下降了10.70%,其他的变化不大。&br&&/p&&p&perf record不一定用于跟踪自己启动的进城,通过指定pid,可以直接跟踪固定的一组进城。另外,大家应该也注意到了,上面给出的跟踪都仅仅跟踪发生在特定pid的事件。但很多模型,比如一个webserver,你其实关心的是整个系统的性能,网络上会占掉一部分CPU,WebServer本身占一部分CPU,存储子系统也会占据部分的CPU,网络和存储不一定就属于你的WebServer这个pid。所以,对于全系统调优,我们常常给record命令加上-a参数,这样可以跟踪整个系统的性能。比如,还是前面这个cs程序的跟踪,如果我用-a命令去跟踪,得到的结果就和原来很不一样了:&/p&&p&&figure&&img data-rawheight=&530& data-rawwidth=&977& src=&/50/8e98a335ece6fabb59f96ddb_b.png& class=&origin_image zh-lightbox-thumb& width=&977& data-original=&/50/8e98a335ece6fabb59f96ddb_r.png&&&/figure&大家注意一下Command那一列。那里已经不仅仅有cs这个进程了。&/p&&p&perf report是一个菜单接口,可以一直展开到每个函数的代码的,例如我们要展开上面这个heavy_cal()函数的具体计数,我们在上面回车,选择代码分析,我们可以得到:&/p&&figure&&img data-rawheight=&468& data-rawwidth=&603& src=&/50/c09106dc4dcbad72e61a021ff6168a40_b.png& class=&origin_image zh-lightbox-thumb& width=&603& data-original=&/50/c09106dc4dcbad72e61a021ff6168a40_r.png&&&/figure&&br&&p&perf record还有其他参数可以控制,例如可以通过-c指定事件的触发的事件次数等,那个读者们可以自己看手册。&/p&&p&和perf record/report类似的还有一个perf stat命令,这个命令不计算分布,仅仅进行统计,类似这样:&/p&&p&&figure&&img data-rawheight=&304& data-rawwidth=&964& src=&/50/8a6bb964dafc_b.png& class=&origin_image zh-lightbox-thumb& width=&964& data-original=&/50/8a6bb964dafc_r.png&&&/figure& 一般情况下,我觉得这个功能用不上。&br&&/p&&p&==堆栈跟踪==&/p&&p&perf的跟踪有一个错觉需要我们注意,假设我们有一个函数abc(),调用另一个函数def(),在perf的统计中,这两者是分开统计的,就是说,执行def的时间,是不计算abc的时间的,图示如下:&/p&&p&&figure&&img data-rawheight=&210& data-rawwidth=&926& src=&/50/208e1c43d41adeb224b12b0_b.png& class=&origin_image zh-lightbox-thumb& width=&926& data-original=&/50/208e1c43d41adeb224b12b0_r.png&&&/figure&这里,abc()被击中5次,def()被击中5次,ghi被击中1次。这会给我们不少错觉,似乎abc的计算压力不大,实际上不是,你要把def和ghi计算在内才行。&/p&&p&但这又带来另一个问题:可能def不仅仅是abc这个函数调用啊,别人也会调用它呢,这种情况,我们怎么知道是谁导致的?&/p&&p&这种情况我们可以启动堆栈跟踪,也就是每次击中的时候,向上回溯一下调用栈,让调用者也会被击中,这样就就更容易看出问题来,这个原理类似这样:&/p&&p&&figure&&img data-rawheight=&217& data-rawwidth=&899& src=&/50/64e0c0e19caaac6e795dc89_b.png& class=&origin_image zh-lightbox-thumb& width=&899& data-original=&/50/64e0c0e19caaac6e795dc89_r.png&&&/figure&这种情况,abc击中了11次,def击中了6次,而ghi击中了1次。这样我们可以在一定程度上更容易判断瓶颈的位置。-g命令可以实现这样的跟踪,下面是一个例子:&/p&&p&&figure&&img data-rawheight=&425& data-rawwidth=&1077& src=&/50/54cddcb2d899c330cfc8fa_b.png& class=&origin_image zh-lightbox-thumb& width=&1077& data-original=&/50/54cddcb2d899c330cfc8fa_r.png&&&/figure&使用堆栈跟踪后,start_thread上升到前面去了,因为正是它调的heavy_cal。&/p&&p&使用堆栈跟踪要注意的是,堆栈跟踪受扫描深度的限制,太深的堆栈可能回溯不过去,这是有可能影响结果的。&/p&&p&另一个问题是,有些我们从源代码看来是函数调用的,其实在汇编一级并不是函数调用。比如inline函数,宏,都不是函数调用。另外,gcc在很多平台中,会自动把很短的函数变成inline函数,这也不产生函数调用。还有一种是,fastcall函数,通过寄存器传递参数,不会产生调用栈,也有可能不产生调用栈,这个通过调用栈回溯是有可能看不到的。&/p&&p&还有一种更奇葩的情况是,部分平台使用简化的堆栈回溯机制,在堆栈中看见一个地址像是代码段的地址,就认为是调用栈,这些情况都会引起堆栈跟踪上的严重错误。使用者应该对系统的ABI非常熟悉,才能很好驾驭堆栈跟踪这个功能的。&/p&&br&&p&==其他功能==&/p&&p&perf是现在Linux中主推的性能分析工具,几乎每次升级都会有重大更新,连什么benchmarking的功能都做进来了,还有用于专项分析perf-mem这样的命令,用来产生脚本的perf script命令,帮助你用不同的脚本语言分析操作结果。这个用户可以自己看手册去,有前面的基础,这些功能都是很好理解的。&/p&&p&不过特别提一下script命令,虽然它的功能看起来只是用来产生分析脚本的,但我们还常常用来导出原始分析数据,读者可以在perf-record后直接用这个命令来导出结果:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf script
&/code&&/pre&&/div&&p&&figure&&img data-rawheight=&773& data-rawwidth=&1368& src=&/50/6af084a5b368b4dcbccb9a957bf81f47_b.png& class=&origin_image zh-lightbox-thumb& width=&1368& data-original=&/50/6af084a5b368b4dcbccb9a957bf81f47_r.png&&&/figure&这里列出每个击中点,你爱怎么处理这些击中点的数据,就全凭你的想象力了。&br&&/p&&br&&p&==perf跟踪的缺陷== &/p&&p&前面已经强调过了,perf跟踪是一种采样跟踪,所以我们必须非常小心采样跟踪本身的问题,一旦模型设置不好,整个分析结果可能都是错的。我们要时刻做好这种准备。&/p&&p&我特别提醒的是,你每次看perf report的报告,首先要去注意一下总共收集了多少个点,如果你只有几十个点,你这个报告就可能很不可信了。 &br&&/p&&p&另外,我们要清楚,现代CPU基本上已经不用忙等的方式进入等待了,所以,如果CPU在idle(就是没有任务调度,这种情况只要你的CPU占用率不是100%,必然要发生的),击中任务也会停止,所以,在Idle上是没有点的(你看到Idle函数本身的点并非CPU Idle的点,而是准备进入Idle前后花的时间),所以,perf的统计不能用来让你分析CPU占用率的。ftrace和top等工具才能看CPU占用率,perf是不行的。 &/p&&p&perf还有一个问题是对中断的要求,perf很多事件都依赖中断,但Linux内核是可以关中断的,关中断以后,你就无法击中关中断的点了,你的中断会被延迟到开中断的时候,所以,在这样的平台上,你会看到很多开中断之后的函数被密集击中。但它们是无辜的。但更糟糕的事,如果在关中断的时候,发生了多个事件,由于中断控制器会合并相同的中断,你就会失去多次事件,让你的统计发生错误。&/p&&p&现代的Intel平台,基本上已经把PMU中断都切换为NMI中断了(不可屏蔽),所以前面这个问题不存在。但在大部分ARM/ARM64平台上,这个问题都没有解决,所以看这种平台的报告,都要特别小心,特别是你看到_raw_spin_unlock()一类的函数击中极高,你就要怀疑一下你的测试结果了(注意,这个结果也是能用的,只是看你怎么用)。&/p&&br&&p&==小结==&/p&&p&这一篇我们介绍了perf的基本用法,perf通常是我们进行性能分析的第一步,但这一步,要用好也不是那么容易的,我们首先应该掌握它的原理,然后基于一个分析模型逐步用perf来验证我们的猜测,我们才有可能真正发现问题。 &/p&
==介绍==ftrace的跟踪方法是一种总体跟踪法,换句话说,你统计了一个事件到下一个事件所有的时间长度,然后把它们放到时间轴上,你可以知道整个系统运行在时间轴上的分布。这种方法很准确,但跟踪成本很高。所以,我们也需要一种抽样形态的跟踪方法。perf提…
&figure&&img data-rawwidth=&683& data-rawheight=&1024& src=&/v2-c75c5904f9f_b.jpg& class=&origin_image zh-lightbox-thumb& width=&683& data-original=&/v2-c75c5904f9f_r.jpg&&&/figure&&br&&br&&br&&b&慢启动(Slow Start)&/b&&br&亚当隔着山头扔玉米棒子给夏娃,亚当不知道夏娃能接多快,于是一次扔1个,编号为1。&br&&br&夏娃喊2,意思是老娘1号玉米棒子已经收到,准备迎接2号玉米棒子。&br&&br&亚当一次扔2个,编号为2、3。&br&&br&夏娃喊4,准备迎接更多的玉米棒子。&br&&br&亚当一次扔4个,编号为4、5、6、7。&br&&br&夏娃喊8,意思是让玉米棒子来得更猛烈些吧!&br&&br&亚当一次扔8个,编号为8、9、…15。&br&&br&夏娃嘴里一直重复喊编号12,次数为3次,这里传达以下信息:&br&8-11号玉米棒子已经安全到达&br&12号玉米棒子肯定丢了&br&13、14、15号玉米棒子也应该安全到达,否则夏娃只会喊一次12,是13、14、15号玉米触发夏娃重复的叫喊。&br&&br&亚当意识到自己扔太快了,需要降速,降到多少合适呢?降一半,一次扔4个没有问题。&br&&br&
if ( dupacks &= 3 ) {
ssthresh = max( 2 , cwnd / 2 ) ;
这里cwnd =8,所以ssthresh=4。&br&&br&注释:&b&ssthresh (Slow Start Threshold),&/b&慢启动的峰值线,一旦超过该峰值线,则进入拥塞避免。&br&&br&但外面至少还有3个发出的玉米棒子还没有确认(&b&Outstanding Packet&/b&),如果将&br&&br&cwnd = ssthresh=4&br&&br&则意味着亚当最多一次可以扔四个玉米,但3个发出却没有确认的玉米棒子占了3个名额,所以亚当最多一次只能扔一个玉米棒子,发送速率急剧下降,这不合理。&br&&br&&b&快速重传&/b&&br&既然收到夏娃三次重复的确认,说明丢的玉米棒子(12)后的3个已经成功接收,不在空中飞(&b&Flight&/b&),这3个虽然还没有明确地确认,但已经隐含地确认了,所以这3个玉米棒子不应该占据在空中飞玉米的数量,在空中飞的玉米应该是4个,再加上到达夏娃的3个,所以亚当的cwnd (&b&Congestion Window&/b&)应该为7个。&br&&br&cwnd = ssthresh + 3 * SMSS= 4+3=7&br&&br&&b&亚当的快速重传&/b&&br&1)重传12号玉米&br&2)扔16、17、18、19号玉米&br&&br&&b&快速重传结束信号&/b&&br&一旦亚当接到夏娃16号玉米或之后的确认,快速重传/快速修复完成。&br&&br&&b&拥塞避免(Congestion Avoidance) &/b&&br&亚当意识到一次扔4个安全,于是选择以cwnd = ssthresh=4为基准线,如果一次扔4个没有问题,那就一次扔5个、6个,线性增长到夏娃的接收极限。&br&&br&更多扔玉米的故事:&a href=&/question//answer/& class=&internal&&&span class=&invisible&&https://www.&/span&&span class=&visible&&/question/5138&/span&&span class=&invisible&&8497/answer/&/span&&span class=&ellipsis&&&/span&&/a&
慢启动(Slow Start) 亚当隔着山头扔玉米棒子给夏娃,亚当不知道夏娃能接多快,于是一次扔1个,编号为1。 夏娃喊2,意思是老娘1号玉米棒子已经收到,准备迎接2号玉米棒子。 亚当一次扔2个,编号为2、3。 夏娃喊4,准备迎接更多的玉米棒子。 亚当一次扔4个…
今日是端午4天假期的最后一天,自己的2台电脑一台在处理数据,另一台电源适配器也坏掉了。感觉闲来无事,在此就简单聊聊numpy和pandas的各种冷知识、小技巧和疑难杂症。&p&个人觉得关于numpy和pandas的坑太大,不好填,在此就不系统的介绍了,各位可以买些这块的资料先自己看看。&/p&&p&这里就着重聊聊一些使用过程中常用到但教科书里找不着的问题,省的各位朋友还跑去stackoverflow找答案。&/p&&p&问题一、dataframe里面.values,.iloc,.ix,.loc的区别?&/p&&p&只有values是将原本dataframe数据强制转化为numpy格式的数据来索引,其他3个都是对dataframe本身的数据来索引,其中iloc是对基于values的位置来索引调用,loc是对index和columns的位置来索引,而ix则是先用loc的方式来索引,索引失败就转成iloc的方式;&/p&&br&&p&问题二、可否有两层,或2层以上的columns或index?有的话如何索引?&/p&&p&可以,索引的话如果用loc或ix,则默认是用第一层的index或columns,最简单的方式是类似于这样:&/p&&p&example.loc[index1, columns1].loc[index2, columns2]&/p&&br&&p&问题三、list, dict, numpy.ndarray, dataframe数据格式如何转换?&/p&&p&1. list转化为numpy.ndarray:&/p&&p&np.array(example)&/p&&p&2. numpy.ndarray转化为list:&/p&&p&list(example)&br&&/p&&p&3. dict转化为dataframe:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&example['a'] = {'bb':2, 'cc':3}
eee = pd.DataFrame(example)
&/code&&/pre&&/div&&p&4. numpy.ndarray转化为dataframe:&/p&&p&pd.DataFrame(example)&/p&&p&5. dataframe转化为numpy.ndarray:&/p&&p&example.values[:, :]&/p&&br&&br&&p&问题四、numpy.ndarray和dataframe如何填补nan,inf?&/p&&p&1. 对于numpy.ndarray来说:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&example = np.where(np.isnan(example), 0, example)
example = np.where(np.isnan(example), 0, example)
&/code&&/pre&&/div&&p&2. 对于dataframe来说:&/p&&p&既可以用example.fillna(),还可以用example.replace(a, b)&/p&&br&&p&问题五、各种OI的效率快慢问题?&/p&&p&1. npy读写效率最高,但最费硬盘空间,比如np.load(), np.save();&/p&&p&2. csv其次,比如pd.Dataframe.to_csv(),pd.load_csv();&/p&&p&3. txt读写,当然也可以很快,但是需要频繁的split,对格式规范的数据比较麻烦;&/p&&p&4. 至于简单的excel和word,可以用xlrd,xlwt来操作;&/p&&br&&p&问题六、关于常见的os操作,包括新建文件夹、遍历文件夹的操作问题?&/p&&br&&p&1. 新建文件夹:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&if&/span& &span class=&ow&&not&/span& &span class=&n&&os&/span&&span class=&o&&.&/span&&span class=&n&&path&/span&&span class=&o&&.&/span&&span class=&n&&isdir&/span&&span class=&p&&(&/span&&span class=&n&&path_out&/span&&span class=&p&&):&/span&
&span class=&n&&os&/span&&span class=&o&&.&/span&&span class=&n&&makedirs&/span&&span class=&p&&(&/span&&span class=&n&&path_out&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&2. 遍历所有文件和子文件夹:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&for&/span& &span class=&n&&a&/span&&span class=&p&&,&/span& &span class=&n&&b&/span&&span class=&p&&,&/span& &span class=&n&&filenames&/span& &span class=&ow&&in&/span& &span class=&n&&os&/span&&span class=&o&&.&/span&&span class=&n&&walk&/span&&span class=&p&&(&/span&&span class=&n&&path_data&/span&&span class=&p&&):&/span&
&span class=&k&&for&/span& &span class=&n&&filename&/span& &span class=&ow&&in&/span& &span class=&n&&filenames&/span&&span class=&p&&:&/span&
&/code&&/pre&&/div&&p&只遍历当前文件,不包含子文件夹:&/p&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&k&&for&/span& &span class=&n&&a&/span&&span class=&p&&,&/span& &span class=&n&&b&/span&&span class=&p&&,&/span& &span class=&n&&filenames&/span& &span class=&ow&&in&/span& &span class=&n&&os&/span&&span class=&o&&.&/span&&span class=&n&&walk&/span&&span class=&p&&(&/span&&span class=&n&&path_data&/span&&span class=&p&&):&/span&
&span class=&k&&for&/span& &span class=&n&&filename&/span& &span class=&ow&&in&/span& &span class=&n&&filenames&/span&&span class=&p&&:&/span&
&span class=&k&&if&/span& &span class=&n&&a&/span& &span class=&o&&==&/span& &span class=&n&&path_data&/span&&span class=&p&&:&/span&
&/code&&/pre&&/div&&br&&p&问题七、numpy.ndarray和dataframe如何选取满足条件的行和列数据?&/p&&p&1. 根据新的columns来选取:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&frame_[newcolumns]
&/code&&/pre&&/div&&p&2. 根据新的index来选取:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&frame_[frame_.index.isin(newindex)]
&/code&&/pre&&/div&3. 根据某一行或者列的条件来选取:&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&假如是根据dataframe的第一列,必须大于start_time这个常数,frame_ = frame_.ix[:, frame_.ix[0, :] &= start_date]
或者是根据dataframe的第一行,必须大于start_time这个常数,frame_ = frame_.ix[frame_.ix[:, 0] &= start_date, :]
&/code&&/pre&&/div&&br&&p&问题八、如何计算相关性矩阵?&/p&&p&将y和所有x放入到sample = numpy.ndarray下,然后直接np.corrcoef(sample ),默认的是皮尔森相关系数,当然,也可以用ranked correlation,也就是spearman correlation,可以直接用scipy.stats.spearmanr。&br&&/p&&br&&br&&p&问题九、如何取出一串字符串里面的字母或者数字?&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&1. 取出example里面的数字:
int(''.join(x for x in example if x.isdigit()))
2. 取出example里面的字母:
(''.join(x for x in example if x.alpha()))
&/code&&/pre&&/div&&br&&p&问题十、各种merge操作?&/p&&p&1. 纵向merge 格式为numpy.ndarray的数据:&/p&&br&&p&np.hstack((example1, example2))&/p&&p&2. 纵向merge 格式为dataframe的数据,并根据dataframe的index来merge,merge后保留原本各自列的所有index,其他没有该index的列则对应数值为nan:&/p&&br&&p&pd.concat([example1, example2], axis=1)&/p&&p&3. 纵向merge,但是只保留公共的index行:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&example.sort_index(axis=1, inplace=True)
&/code&&/pre&&/div&&p&4. 横向merge格式为numpy.ndarray的数据:&/p&&br&&p&np.vstack((example1, example2))&/p&&p&5. 横向merge 格式为dataframe的数据,并根据dataframe的column来merge,merge后保留原本的index和columns,其他没有该index或columns的列则对应数值为np.nan:&/p&&p&pd.concat([example1, example2], axis=0)&/p&&p&6. 横向merge,但是只保留公共的columns列:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&example.sort_index(axis=0, inplace=True)
&/code&&/pre&&/div&&br&&p&问题十一、对dataframe数据的index统一加一个后缀&/p&&p&比如对原本dataframe下的index=[‘aa’, 'cc', 'dddddd']的,统一加上一个_5m的后缀,通常的操作大家一般就是直接example.index = [x + '_5m' for x in example.index],这个其实会产生些小问题,因为默认的index是pandas.indexes.base.Index,这个格式可能会默认index里面数据的长度是确定的,导致加_5m后缀失败,所以需要先把格式强制转化为list, 像这样:example.index = [x + '_5m' for x in list(example.index)]&/p&&br&&br&&p&先就这些吧,其他的想到再慢慢加。&/p&
今日是端午4天假期的最后一天,自己的2台电脑一台在处理数据,另一台电源适配器也坏掉了。感觉闲来无事,在此就简单聊聊numpy和pandas的各种冷知识、小技巧和疑难杂症。个人觉得关于numpy和pandas的坑太大,不好填,在此就不系统的介绍了,各位可以买些这块…
推荐 Agner Fog 的 5 本优化手册:&br&&ol&&li&Optimizing software in C++: An optimization guide for Windows, Linux and Mac platforms&br&&/li&&li&Optimizing subroutines in assembly language: An optimization guide for x86 platforms&br&&/li&&li&The microarchitecture of Intel, AMD and VIA CPUs: An optimization guide for assembly programmers and compiler makers&br&&/li&&li&Instruction tables: Lists of instruction latencies, throughputs and micro-operation breakdowns for Intel, AMD and VIA CPUs&br&&/li&&li&Calling conventions for different C++ compilers and operating systems&br&&/li&&/ol&&a href=&///?target=http%3A//www.agner.org/optimize/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Software optimization resources. C++ and assembly. Windows, Linux, BSD, Mac OS X&i class=&icon-external&&&/i&&/a&。
推荐 Agner Fog 的 5 本优化手册: Optimizing software in C++: An optimization guide for Windows, Linux and Mac platforms Optimizing subroutines in assembly language: An optimization guide for x86 platforms The microarchitecture of Intel, A…
&b&编程范式&/b&&br&函数式编程是一种编程范式,我们常见的编程范式有&b&命令式编程(Imperative programming)&/b&,&b&函数式编程&/b&,&b&逻辑式编程&/b&,常见的面向对象编程是也是一种命令式编程。&br&&br&命令式编程是面向&b&计算机硬件&/b&的抽象,有&b&变量&/b&(对应着存储单元),&b&赋值语句&/b&(获取,存储指令),&b&表达式&/b&(内存引用和算术运算)和&b&控制语句&/b&(跳转指令),一句话,命令式程序就是一个&b&冯诺依曼机&/b&的&b&指令序列&/b&。&br&&br&而函数式编程是面向数学的抽象,将计算描述为一种&b&表达式求值&/b&,一句话,函数式程序就是一个&b&表达式&/b&。&br&&br&&b&函数式编程的本质&/b&&br&函数式编程中的&b&函数&/b&这个术语不是指计算机中的函数(实际上是&b&Subroutine&/b&),而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的。&br&&br&在函数式语言中,&b&函数作为一等公民&/b&,可以在任何地方定义,在函数内或函数外,可以作为函数的参数和返回值,可以对函数进行组合。&br&&br&纯函数式编程语言中的&b&变量&/b&也不是命令式编程语言中的变量,即存储状态的单元,而是代数中的变量,即一个值的名称。变量的值是&b&不可变&/b&的&b&(immutable)&/b&,也就是说不允许像命令式编程语言中那样多次给一个变量赋值。比如说在命令式编程语言我们写“x = x + 1”,这依赖可变状态的事实,拿给程序员看说是对的,但拿给数学家看,却被认为这个等式为假。&br&&br&函数式语言的如条件语句,循环语句也不是命令式编程语言中的&b&控制语句&/b&,而是函数的语法糖,比如在Scala语言中,&b&if else&/b&不是语句而是三元运算符,是有返回值的。&br&&br&严格意义上的函数式编程意味着不使用可变的变量,赋值,循环和其他命令式控制结构进行编程。&br&&br&从理论上说,函数式语言也不是通过&b&冯诺伊曼体系结构&/b&的机器上运行的,而是通过&b&λ演算&/b&来运行的,就是通过&b&变量替换&/b&的方式进行,变量替换为其值或表达式,函数也替换为其表达式,并根据运算符进行计算。λ演算是&b&图灵完全(Turing completeness)&/b&的,但是大多数情况,函数式程序还是被编译成(冯诺依曼机的)机器语言的指令执行的。&br&&br&&b&函数式编程的好处&/b&&br&由于命令式编程语言也可以通过类似函数指针的方式来实现高阶函数,函数式的最主要的好处主要是不可变性带来的。没有可变的状态,函数就是&b&引用透明(Referential transparency)&/b&的和&b&没有副作用(No S&/b&&b&ide Effect&/b&&b&)&/b&。&br&&br&一个好处是,函数即不依赖外部的状态也不修改外部的状态,函数调用的结果不依赖调用的时间和位置,这样写的代码容易进行推理,不容易出错。这使得单元测试和调试都更容易。&br&&br&不变性带来的另一个好处是:由于(多个线程之间)不共享状态,不会造成&b&资源争用(Race condition)&/b&,也就不需要用&b&锁&/b&来保护可变状态,也就不会出现&b&死锁&/b&,这样可以更好地并发起来,尤其是在&b&对称多处理器&/b&(SMP)架构下能够更好地利用多个处理器(核)提供的并行处理能力。&br&&br&2005年以来,计算机计算能力的增长已经不依赖CPU主频的增长,而是依赖CPU核数的增多,如图:&br&&figure&&img src=&/fbdaf_b.jpg& data-rawwidth=&871& data-rawheight=&868& class=&origin_image zh-lightbox-thumb& width=&871& data-original=&/fbdaf_r.jpg&&&/figure&(图片来源:&a href=&///?target=http%3A//www.gotw.ca/publications/concurrency-ddj.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software&i class=&icon-external&&&/i&&/a& )&br&&br&图中&b&深蓝色的曲线是时钟周期&/b&的增长,可以看到从2005年前已经趋于平缓。 在多核或多处理器的环境下的程序设计是很困难的,难点就是在于&b&共享的可变状态&/b&。在这一背景下,这个好处就有非常重要的意义。&br&&br&由于函数是引用透明的,以及函数式编程不像命令式编程那样关注执行步骤,这个系统提供了优化函数式程序的空间,包括&b&惰性求值&/b&和并性处理。&br&&br&还有一个好处是,由于函数式语言是面向数学的抽象,更接近人的语言,而不是机器语言,代码会比较简洁,也更容易被理解。&br&&br&&b&函数式编程的特性&/b&&br&由于变量值是不可变的,对于值的操作并不是修改原来的值,而是修改新产生的值,原来的值保持不便。例如一个Point类,其moveBy方法不是改变已有Point实例的x和y坐标值,而是返回一个新的Point实例。&br&&div class=&highlight&&&pre&&code class=&language-scala&&&span class=&k&&class&/span& &span class=&nc&&Point&/span&&span class=&o&&(&/span&&span class=&n&&x&/span&&span class=&k&&:&/span& &span class=&kt&&Int&/span&&span class=&o&&,&/span& &span class=&n&&y&/span&&span class=&k&&:&/span& &span class=&kt&&Int&/span&&span class=&o&&){&/span&
&span class=&k&&override&/span& &span class=&k&&def&/span& &span class=&n&&toString&/span&&span class=&o&&()&/span& &span class=&k&&=&/span& &span class=&s&&&Point (&&/span& &span class=&o&&+&/span& &span class=&n&&x&/span& &span class=&o&&+&/span& &span class=&s&&&, &&/span& &span class=&o&&+&/span& &span class=&n&&y&/span& &span class=&o&&+&/span& &span class=&s&&&)&&/span&
&span class=&k&&def&/span& &span class=&n&&moveBy&/span&&span class=&o&&(&/span&&span class=&n&&deltaX&/span&&span class=&k&&:&/span& &span class=&kt&&Int&/span&&span class=&o&&,&/span& &span class=&n&&deltaY&/span&&span class=&k&&:&/span& &span class=&kt&&Int&/span&&span class=&o&&)&/span& &span class=&k&&=&/span& &span class=&o&&{&/span&
&span class=&k&&new&/span& &span class=&nc&&Point&/span&&span class=&o&&(&/span&&span class=&n&&x&/span& &span class=&o&&+&/span& &span class=&n&&deltaX&/span&&span class=&o&&,&/span& &span class=&n&&y&/span& &span class=&o&&+&/span& &span class=&n&&deltaY&/span&&span class=&o&&)

我要回帖

更多关于 gre什么意思 的文章

 

随机推荐