turboc2.CFG中的-I和-L是什...

B本题属离子共存题。由题干条件知c(H+)=1×10-12 mol·L-1的溶液的pH=2或pH=12。当溶液呈酸性时,C中的、Fe2+易发生氧化还原反应,D中ClO-、I-发生氧化还原反应;当溶液呈碱性时,A中与OH-生成弱电解质NH3·H2O,C中Fe2+、Mg2+分别与OH-生成了Fe(OH)2、Mg(OH)2沉淀,D中的ClO-、I-仍能发生氧化还原反应。故只有B正确。
请在这里输入关键词:
科目:高中化学
来源:不详
题型:单选题
科目:高中化学
来源:不详
题型:填空题
同浓度的下列溶液中NH4+的浓度的由大到小顺序为&&&&&&&&&&&&&&&&&①NH4HSO4&②(NH4)2SO4&③(NH4)2Fe(SO4)&④NH4HCO3&⑤(NH4)2CO3
科目:高中化学
来源:不详
题型:单选题
不能证明HA是弱酸的是(&&)&&&A.常温下,NaA溶液的pH="9"B.0.01 mol·L-1HA溶液的pH=4C.pH=2的HA溶液稀释100倍后pH="3.5"D.HA溶液跟锌反应,放出H2很慢
科目:高中化学
来源:不详
题型:单选题
下列各组离子在所给的条件下能够大量共存的是&&&A.在Ph=0的溶液中:Fe2+、Mg2+、SO、NOB.由水电离出的c(H+)=1×10mol/L的溶液中:HCO、K+、Na+、S2一C.在AlCl3溶液中:SO、Na+、CO、AlOD.在滴加酚酞试液后呈红色的溶液中:I、AlO、Na+、S
科目:高中化学
来源:不详
题型:单选题
下列各组离子一定能大量共存的是(&&)A.在含有大量[Al(OH)4]-的溶液中:NH4+、Na+、Cl-、H+B.在强碱溶液中:Na+、K+、CO32-、NO3-C.在pH=12的溶液中:NH4+、Na+、SO42-、Cl-D.在c(H+)=0.1mol·L-1的溶液中:K+、I-、Cl-、NO3-
科目:高中化学
来源:不详
题型:单选题
下列各组离子,能在溶液中大量共存的是A.&&&&B C.&&&&& D
科目:高中化学
来源:不详
题型:单选题
下列离子能在溶液中大量共存,当将溶液的pH调节至1时就会出现浑浊的是(  )A.Fe2+、Fe3+、NH4+、NO3-B.S2-、K+、I-、SO32-C.Na+、I-、CO32-、NO3-D.Al3+、HCO3-、OH-、Na+
科目:高中化学
来源:不详
题型:单选题
在强碱性溶液中能大量共存的离子组是(  )A.Al3+、Cu2+、NO3-、Cl-B.Na+、NO3-、SO42-、HCO3-C.Ba2+、K+、OH-、Cl-D.Mg2+、NH4+、SO42-、Cl-请问Linux 命令 ls -l 后出现的是什么意思_百度知道
请问Linux 命令 ls -l 后出现的是什么意思
baidu.jpg" esrc="http. 这些行&nbsp.baidu.hiphotos:///zhidao/wh%3D600%2C800/sign=179a2ff537d3d539cc568/267f9e2fd31fb999a://g.jpg" />请高手帮忙解决一下&/zhidao/wh%3D450%2C600/sign=e48300bce42d0c/267f9e2fd31fb999a.jpg" target="_blank" title="点击查看大图" class="ikqb_img_alink"><img class="ikqb_img" src="/zhidao/pic/item/267f9e2fd31fb999a.hiphotos://g<a href="http
提问者采纳
31 testfile最后用ls -l 看到第三字段的文件拥有者为gucuiwen然后我将gucuiwen用户删除.############################### 第7字段:[root@gucuiwen root]# useradd gucuiwen -g users [root@gucuiwen root]# su - gucuiwen用新建的用户创建一个测试文件;devices/XFree86其中的s表示这个是网络接口程序&quot.cfg表示文件的拥有者root对文件有读写权限.hardlink可以看到.这些文件头可以指向同一个文件;X11R6&#47,是很特殊的文件.如;sysconfig/bin&#47.该程序在运行过程中会打开一个网络接口.以下是演示.当然. 如果我用ln,那么会有一个 &quot,无论是修改哪一个文件,windows中不允许一个文件有两个以上文件名,只有一个主设备号和一个辅设备号,或者具有写权限的用户才有在目录下创建文件的权利; 箭头符号,也就是该目录的大小;BEGIN{sum=0}{sum+=$5}END{print sum}&#39,可以用DEBUG修改一张软盘上的根目录,每个文件都有它的拥有者.############################### 第4字段;etc -inum 147181 &#47:-rw-r--r-- 1 root root 1581 11月 24 18: 文件属性字段 ########################文件属性字段总共有10个字母组成,是dirtectory(目录)的缩写;devices/ [root@gucuiwen gucuiwen]# ls -l 总用量 0 -rw-r--r-- 1 501 users 0 1月 4 16,要么全不让看;&XFree86 -rws--x--x 1 root root 3-02-28 &#47,,那么用ls -l 查看该文件将显示一个代表用户存在前ID号的数字,光盘等.请注意是文件夹本身的大小.可以在adduser的时候用-g指定该用户所在的主组.cfg anaconda-ks,第三字段成了一个数字,比如键盘.这个数字和du &#47,一次传输一个字节的设备被称为字符设备,其他人(同组用户和其他用户只有读的权限)另外,这个文件所具有的硬链接数.############################### 第3字段: **************************************如果是一个目录.cfg这一个文件名.它的没有文件大小.即只有一个指向该链接的硬链接.开头为b的表示块设备文件(block),后面根一个它指向的文件名,这样的话理解文件夹大小的含义就比较困难了;bin/ifcfg-eth0 147181 &#47,最后修改时间等属性;,这个文件所占用的空间才真正被释放.用ls -a可以看到;networking&#47.第一字段的后面9个字母表示文件的权限: 文件名 ###############################如果是一个符号链接;1024}&#39,这个数字是原gucuiwen用户的ID号.&d&quot.比如&#47.,该目录第2字段的值就增1: 文件拥有者 ###############################该字段表示这个文件是属于哪个用户的,表示该文件是一个符号链接;s&quot.只有文件的拥有者才具有改动文件属性的权利;home&#47: 文件创建时间 ############################### 文件创建的时间可以通过touch命令来修改,这两个文件具有相同的文件节点号.请注意;:[root@gucuiwen root]# ls -l |awk &#39,具有主设备号3和辅设备号1;X11R6&#47.&quot.请注意和该目录下的文件和子目录下文件的总合做区分;etc&#47,则说明该文件是一个普通文件; 4007,而不是文件夹以及它下面的文件的总大小;XFree86具有如下权限,而非用户名: 总用量 4055用du -sh &#47,因为实际上他们指向同一个文件,可以控制文件让特定的用户查看,第2字段的含义;ifcfg-eth0这样就得到了同一个文件的不同文件名的位置,anaconda-ks.************************************* 如果是一个目录;root可以看到累加第5个字段得到的值和total显示的是一样的(因为具体算法的不同,如果存在这中情况,用-G指定其他组,被删除;sysconfig&#47,权限组还有一些特殊的表示法.cfg.而不是一棍子打死,表示一个临时(temporary)文件 在freeBSD中用ls -l &#47.如果某一个用户因为某种原因;root 得到的数字的大小是不一样的:[gucuiwen@gucuiwen gucuiwen]$ touch testfile [gucuiwen@gucuiwen gucuiwen]$ ls -l testfile -rw-r--r-- 1 gucuiwen users 0 1月 4 16;: 文件文件大小(以字节为单位) ###############################第5字段表示文件大小可以看到,但是其中有一个是主组:先创建一个用户并用su过去, root用户具有改动任何文件属性的权利;-&gt.hardlink [root@gucuiwen root]# ls -l 总用量 4071 -rw-r--r-- 2 root root 1581 11月 24 18.cfg第2字段的值为1;root 127M &#47:[root@gucuiwen root]# ln anaconda-ks,只有拥有该目录的用户,最后三个表示其他用户权限;d&############################### 第2字段 文件硬链接数或目录子目录数 ###############################如果一个文件不是目录那么这一字段表示;bin&#47,一个目录或者说一个文件夹是一个特殊文件. touch的详细用法请看链接文档.可以用awk命令来验证.sysconfig&#47,如何查找他的其他文件名分布在什么地方呢;ifcfg-eth0就具有多个文件名: 文件创建日期 ############################################################## 第8字段;;是socket的缩写.############################### 第9字段.每次在目录下新建一个子目录.如果该字母是&quot.如果你以前在windows下玩过DEBUG就知道:[root@gucuiwen root]# ll &#47? 因为每一个目录都有一个指向它本身的子目录&quot,这两个默认子目录是隐藏的;etc/.其他UNIX类系统如FreeBSD中还有t权限; 和指向它上级目录的子目录&quot. 比如;tmp 可以看到这样的权限,设备文件是普通文件和程序访问硬件设备的入口. r表是读 (Read) w表示写 (Write) x表示执行 (eXecute)其中前三个表示文件属主的权限. 这些属性可以用ls 的其它参数显示出来.cfg 18102 anaconda-ks.l&quot.用awk累加第5字段得到的数值,该文件的第2字段就会变成2.############################### 第6字段! 很多人不能理解文件夹是一个特殊的文件的含义.############################### 第5字段;X11R6&#47.UNIX类系统都是多用户系统;default/profiles/usr&#47.字母&etc/ifcfg-eth0 &#47,但是新建一个普通文件该字段值不增加.cfg [root@gucuiwen root]# ls -i anaconda-sysconfig&#47: [root@gucuiwen root]# du -sh &#47,一个文件可以有多个文件名.####################### 第1行.在UNIX类系统中;etc&#47,一个文件的多个文件名之间互称为硬链接(hard link):[root@gucuiwen devices]# find &#47,删除其中一个文件名并不能删除该文件,另一个里也做相应的变化;ifcfg-eth0得到它的节点号为 147181 再用find查找:31 testfile可以看到,则表示该文件夹的大小;-&quot:[root@gucuiwen root]# ls -i anaconda-ks.cfg 和anaconda-ks,该文件才真正被删除,用ls -l命令查看某一个目录会得到一个9个字段的列表: #touch testfile 可以把testfile的创建时间修改为当前时间?可以先用ls -i 获得它的节点号.通过组的概念.上面的hda1就是一个设备文件.最小数据传输单位为一个数据块(通常一个数据块的大小是512字节);sysconfig/BEGIN{sum=0}{sum+=$5}END{print sum&#47: 文件拥有者所在的组 ###############################组的概念可以想像成是一个共同完成一个项目的团队; 4104092转化成以K为单位.######################## 第1字段.因为文件系统对每个文件记录文件所有者的ID;l&quot,这个目录的第二字段就是2.hardlink 18102 anaconda-ks:14 anaconda-ks,说明这个文件只有anaconda-ks,做一个指向该文件的硬链接再查看该文件.cfg,就是显示在第4字段的明称:18102如果你知道一个文件有多个文件名: 文件创建月份 ############################### 这个不必多说了,这个特殊文件存放的是其他文件和文件夹的相关信息:[root@gucuiwen devices]# ls -i &#47,如果是一个文件夹;t&quot.对于一个目录来说.为什么新建的目录下面会有两个子目录呢,使一个文件同时具有两个文件名;root得到的数值.符号链接的概念类似于windows里的快捷方式,修改或运行:14 anaconda-ks: drwxrwxrwt 它的最后一位是字母&quot.一次传输数据为一整块的被称为块设备,略微有差别).查看第一个文件. 新建一个空目录.他们指向同一个文件,如果第一个字母为c表示该文件是一个字符设备文件(character).得到的数值实际上是root目录的大小(把root目录看成是一个特殊的文件.一个用户可以加入很多个组.hardlink此时;devices/networking/usr/devices&#47.cfg -rw-r--r-- 2 root root 1581 11月 24 18,要么全让看;etc&#47,如&#47,就可以理解什么是目录的大小):[root@gucuiwen root]# ls -l |awk &#39;networking&#47.用ls -i anaconda-ks,第一个字母表示文件类型:总用量(total) ####################### 这个数值是该目录下所有文件及目录列表第5个字段的和(以k为单位).hardlink 称为互为硬链接;表示该文件是一个目录;gucuiwen&#47.而用du得到的数值是root目录下所由文件和子目录下全部文件的大小的总合;networking&#47,只有把指向该文件的所有硬链接都删除,比如硬盘,我要查找与它互为硬链接的文件.cfg,中间三个表示组用户权限,如果这个字母是一个减号&quot:-rw-r--r-- 1 root root 1581 11月 24 18;usr&#47. 以下是验证实验:[root@gucuiwen root]# userdel gucuiwen [root@gucuiwen root]# cd &#47.cfg可以查看它的文件节点(inode) 互为硬链接的文件具有相同的文件节点,则第2字段表示该目录所含子目录的个数,然后用find查找;.这和windows是有很大区别的,而该用户的文件还存在,字符终端等,表示该目录下有两个子目录.表示第一个硬盘第一个分区.字母&quot.9用ls -l得到的数值,一个文件还有最后访问时间,则被认为是文件系统错误:14 anaconda-ks.但是修改好后用 scandisk监测的时候会被认为是交叉链接错误,传输数据的最小单位为一个字节. #man touch另外;networking&#47,字母&quot:14 anaconda-是link(链接)的缩写,即这个文件总共有多少个文件名.另外
提问者评价
来自团队:
其他类似问题
为您推荐:
其他5条回答
蓝色的为文件夹, 第一列为其权限r是读x是执行w是写 第二列的数字是其连接的个数 第三列是 拥有者 第四列是所有的工作组 第五列是大小(kb) 后面是创建修改时间,后面是文件名。
前面的rwx代表的是这些文件的权限 r :可读,w:可写,w:可执行root
就是根目录了,其他的就是时间和文件名了
-rw-r--r--
1 user root
1022 Feb 13 16:07 anaconda-ks.cfg这些都是文件的属性,包括文件(-)、:1)(user)的权限为rw-、拥有读和写,2)组(root):r--,拥有读权限3)其他成员,r--,拥有读权限 4)122表示文件的大小,5)Feb 13 16:07是文件的修改时间。
这些都是当前目录下的文件和目录名列表.这个列表包含了文件的属性,所属用户,所属组,创建时间,文件大小等等信息.具体说明参考: PS:能自己了解的东西,最后自己找。。动手才重要!
建议买本Linux书学习..
linux的相关知识
下载知道APP
随时随地咨询
出门在外也不愁B分析:A.离子之间发生氧化还原反应;B.该组离子之间不反应;C.pH试纸呈红色的溶液,显酸性,离子之间发生氧化还原反应;D.由水电离的c(H+)=10-12mol/g?L-1的溶液,为酸或碱溶液.解答:A.H+、I-、ClO-离子之间发生氧化还原反应,则不能大量共存,故A错误;B.该组离子之间不反应,能大量共存,故B正确;C.pH试纸呈红色的溶液,显酸性,H+、Fe2+、NO-3离子之间发生氧化还原反应,则不能共存,故C错误;D.由水电离的c(H+)=10-12mol/g?L-1的溶液,为酸或碱溶液,NH4+、OH-结合生成弱电解质,H+分别与碳酸根离子、亚硫酸根离子反应,则不能共存,故D错误;故选B.点评:本题考查离子的共存,明确习题中的信息及常见离子之间的反应是解答本题的关键,注意选项AC为解答的难点,题目难度不大.
请在这里输入关键词:
科目:高中化学
(2009?滨州模拟)可能大量存在的离子组是(  )A.无色溶液中:H+、Na+、I-、ClO-B.含有&HCO3-的溶液中:K+、Na+、SO32-、SO42-C.使pH试纸呈红色的溶液中:K+、Fe2+、NO-3、Cl-D.由水电离的c(H+)=10-12mol/g?L-1的溶液中:-、CO2-3、SO2-3
科目:高中化学
(2008?枣庄一模)向存的大量Na+、Cl-的溶液中通入足量的NH3后,该溶液中还可能大量存在的离子组是(  )A.K+、Br-、CO32-B.Al3+、H+、MnO4-C.NH4+、Fe3+、SO42-D.Ag+、Ca2+、NO3-
科目:高中化学
下列情况溶液中可能大量存在的离子组是(  )①无色溶液中:H+、Na+、Cl-、MnO4-②pH=7的溶液中:Na+、Ca2+、Cl-、HCO3-③使石蕊试液呈蓝色的溶液中:K+、SO42-、ClO-、Cl-④常温下,由水电离产生的c(H+)=10-12mol/L的溶液中:Na+、Cl-、CO32-、SO42-⑤某含SO42-的溶液中:Na+、Ba2+、Cl-、OH-⑥某含Fe3+的溶液中:NH4+、Cl-、NO3-、SCN-.A.②③B.②④⑤C.⑤⑥D.③④
科目:高中化学
向含大量Na+、Cl-的溶液中通入足量的NH3后,该溶液中还可能大量存在的离子组是(  )A.K+、Br-、CO32-B.Al3+、H+、MnO4-C.NH4+、Ba2+、NO3-D.Ag+、Cu2+、SO42-
科目:高中化学
向存在大量Na+、NO3-的溶液中通入足量NH3后,溶液中还可能大量存在的离子组是(  )A、Al3+、H+、MnO4-B、K+、Br-、CO32-C、Ag+、Cu2+、NO3-D、NH4+、Fe2+、SO42-目前来看纯手工编写CUDA代码的人已经从自由竞争阶段进入垄断阶段。主要原因无非是官方发布的SDK工具并不是最高效的实现,而是存在一定认知“黑洞”,一般用户无论如何优化CUDA C程序都无法逾越性能瓶颈。而官方发布的库,从早期的CUBLAS,CUFFT到后来面向深度学习的CUDNN,都不是用CUDA C写的,而是NVIDIA内部的编译器完成的(这个是没有公开的版本),这样对NVIDIA好处显而易见,既能卖硬件,又能在软件上保持领先,增加用户粘度。从用户角度而言,使用高度封装的库可以降低开发、调试的门槛,直接调用C API就可以实现自己的算法,无需了解CUDA C的设计细节。&br&&br&对于性能要求近乎苛刻的应用,则需要利用PTX、SASS汇编指令进行深度优化,为此自己需要开发一些工具,也有开源的asfermi, asmaxwell。&br&&br&所以,用户完全可以避开手动写CUDA C代码,而按照这个步骤优化自己的应用:&br&1. 使用CPU实现;&br&2. 使用CPU上的数学库,如MKL,OpenBLAS,ATLAS,FFTW等进行加速;&br&3. 使用GPU上的数学库,如CUBLAS,CUFFT,调用接口与2类似,改动很小;&br&4. 使用GPU上的专业库,如CUDNN;&br&5. 如果上述都不能满足你的性能要求,要么是你使用方式有问题,要么是你的GPU太挫。&br&6. 请忽略5. 把关键代码进行汇编级别优化。&br&7. 待续。。。&br&&br&看的学术论文里面提到使用CUDA C开发的程序相比之前有了数千倍加速,其实是baseline设得太low了,上述步骤1和步骤6没有可比性。读者应自行甄别。
目前来看纯手工编写CUDA代码的人已经从自由竞争阶段进入垄断阶段。主要原因无非是官方发布的SDK工具并不是最高效的实现,而是存在一定认知“黑洞”,一般用户无论如何优化CUDA C程序都无法逾越性能瓶颈。而官方发布的库,从早期的CUBLAS,CUFFT到后来面向深…
实际工程代码基本是清晰第一,效率第二的,所以下面大多数奇技淫巧适用的场景大部分是ACM之类的&br&&br&1.超快速读入&br&现在快速读入已经不算黑科技了吧,下面这个读入在hdu上面速度比快速读入快&br&const int BUFSIZE=120&&20;&br&char Buf[BUFSIZE+1],*buf=B&br&template&class T&&br&inline void scan(T&a){&br&
for (a=0;*buf&'0'||*buf&'9';buf++);&br&
while (*buf&='0'&&*buf&='9'){a=a*10+(*buf-'0');buf++; }&br&}&br&&br&fread(Buf,1,BUFSIZE,stdin);&br&&br&&br&2.扩栈,系统栈在windows下有限,爆了怎么办?&br&#pragma comment(linker, &/STACK:2400000&)&br&&br&3.vim写代码用到c++11的特性老是要编译的时候加上-std=c++11,直接在程序上加:&br&#pragma GCC diagnostic error &-std=c++11&&br&&br&4.同样类型的黑科技,程序里面开O3优化__attribute__((optimize(&-O3&)))&br&&br&5.09年骆可强论文中提到的各种黑科技:&br&&br&为了消除分支预测,可以把绝对值写成:&br&&div class=&highlight&&&pre&&code class=&language-text&&inline int abs(int x)
int y = x && 31;
return (x + y) ^
&/code&&/pre&&/div&&br&&br&max函数写成:&br&&div class=&highlight&&&pre&&code class=&language-cpp&&&span class=&kr&&inline&/span& &span class=&kt&&int&/span& &span class=&nf&&max&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&,&/span& &span class=&kt&&int&/span& &span class=&n&&y&/span&&span class=&p&&)&/span&
&span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&n&&y&/span&&span class=&o&&&&/span&&span class=&p&&((&/span&&span class=&n&&x&/span&&span class=&o&&-&/span&&span class=&n&&y&/span&&span class=&p&&)&/span&&span class=&o&&&&&/span&&span class=&mi&&31&/span&&span class=&p&&)&/span&&span class=&o&&|&/span&&span class=&n&&x&/span&&span class=&o&&&~&/span&&span class=&p&&((&/span&&span class=&n&&x&/span&&span class=&o&&-&/span&&span class=&n&&y&/span&&span class=&p&&)&/span&&span class=&o&&&&&/span&&span class=&mi&&31&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&&br&&br&&br&计算两个int的平均数(也是整数),x,y两数相加可能会溢出,可以写成:&br&&div class=&highlight&&&pre&&code class=&language-text&&int average = (x & y) + ((x ^ y) && 1)
&/code&&/pre&&/div&&br&&br&为了使cache命中率更高,尽量避免2的幂次方长度的数组&br&&br&6.c/c++里大括号{
%&互换..........并不知道这有什么意义&br&&br&&br&7.在某些场合使用以下代码估计很多人已经熟悉了,但第一次看到下面代码还是费解了半天&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&cp&&#define st(x) do { x } while (__LINE__ == -1)&/span&
&/code&&/pre&&/div&&br&&br&8.针对OJ的,某些OJ的long long是%lld有些是%I64d,是不是还在一个一个改?&br&可以这样巧妙的利用宏:&br&&div class=&highlight&&&pre&&code class=&language-text&&#define LLD &%lld&
&/code&&/pre&&/div&&br&&br&比如输出就可以printf(&output: &LLD&\n&, x);&br&然后就可以只改一个了&br&&br&9.两个long long 相乘然后mod p,相乘以后可能会溢出,古有快速幂,现有快速乘法,这个的普及程度现在基本上也不算黑科技了&br&&div class=&highlight&&&pre&&code class=&language-text&&long long multiply(long long x,long long y,long long p)// x * y % p
long long ret = 0;
for(; y &&= 1)
if(y & 1)ret = (ret + x) %
x = (x + x) %
&/code&&/pre&&/div&
实际工程代码基本是清晰第一,效率第二的,所以下面大多数奇技淫巧适用的场景大部分是ACM之类的1.超快速读入现在快速读入已经不算黑科技了吧,下面这个读入在hdu上面速度比快速读入快const int BUFSIZE=120&&20;char Buf[BUFSIZE+1],*buf=Btemplate&class T…
对于尚处于发展阶段的技术,抱有任何成pian见都是有害的。&br&&br&
结构网格和非结构网格之争,本来就是一笔糊涂账,说它是糊涂账,一是因为里面不确定的因素太多,大多数对结构网格和非结构网格优缺点的评论都是受制于评论者自身的视野和手头的实现工具,而且几乎所有评论的正确性都是局部的、暂时的,一旦言之凿凿就立刻(或者在不久的将来)有反对者站出来打脸,这对争论的任何一方都适用。所以我写出下面的私货时,已经做好被打脸的准备了,必须匿名。&br&&br&
结构网格的好处,最大的好处,就在于其在单块内空间拓扑结构简单,方向明晰,逻辑直观。研究者能把精力从复杂的拓扑结构考量中解放出来,更多的去关注求解的模型和算法本身上去。在这点上朱辉说了句大实话,非结构网格的求解器从实现上确实比较难一些。但是编不出来丢不丢人?我觉得不丢人,专注于问题本身,将精力尽量集中到我们关心的问题上去不对么?找到适合假设(仅仅是假设)让我去做开发一种新的(注意是新的)湍流模型,或者新的离散格式这种基础研究,我会优先考虑使用结构网格,一来代码简单,玩具级别的求解器就能把这事干了。二来结构网格可控性强,我不用为了流场的局域加密这点破事还要额外再学一堆流场网格加密的控制技术。三来我有强迫症,看到非结构网格那种冰糖状的流场截面就不舒服,分析流场有可能因为心理原因得不出正确的结果。所以说,结构网格在易用性这点上还是有点优势的。看当下CFD研究,基本上是一个功能,结构网格一派先提出了,发了论文,balabala各种秀,然后非结构网格很快跟进,啪啪啪打脸说你这个功能我也是可以的。除了易用性这点,结构网格别的所有优点几乎都能找到非结构网格版的替代,或者在可见的将来被替代。结构网格当下虽然如日中天,但是在可预见的将来其在复杂外形流场模拟领域的应用空间会随着非结构网格的跟进压缩的越来越窄。因为结构网格的自动化生成问题,几乎无法解决。应对复杂几何外形,Icemcfd的出现可以说是革命性的,但这是一条死路,基于ICEM脚本的多块网格自动化生成上世纪90年代就有了,就是拓扑结构相似的网格只做一套,对不破坏原拓扑结构的几何变动通过脚本实现自动化生成。但直到现在也没什么革命性的突破。另外,icem生成的网格质量也很有槽点,需要相当多的针对性练习才会保证其质量。任意拓扑结构的多块网格自动化生成可以说是一个天坑。目前另外一个有意思的方向是基于重叠网格的空间结构网格生成,gridgen 和pointwise近年来一直往这方面发力,嵌套网格带来的插值误差等问题让我不看好这一方向。一切都有变数,流体界人才济济,没准在世界某个角落正有人捣鼓你我都不知道的黑科技。比如随着计算能力的提升,笛卡尔网格这一快要灭绝的祖宗级网格技术居然老树发新芽,死灰复燃,不管多复杂的外形,我可劲的加密,反正计算量不是问题,让人不得不感叹一切皆有可能。&br&&br&
非结构网格的最初优势在于自动化,这几乎就是瞄着结构网格的痛脚去的。而且随着非结构网格一派人才辈出,大家很快就发现非结构网格这东西的好处远远不止这一点,动边界,区域自适应加密,等等。一旦接受了非结构网格那种让人不舒服的空间划分方式,你就会发现非结构网格这东西几乎无所不能,所有基于结构网格的实现都有非结构网格的替代,虽然实现的学习成本和研究成本比较高。&br&&br&
先写这么多,有时间以后补充。
对于尚处于发展阶段的技术,抱有任何成pian见都是有害的。 结构网格和非结构网格之争,本来就是一笔糊涂账,说它是糊涂账,一是因为里面不确定的因素太多,大多数对结构网格和非结构网格优缺点的评论都是受制于评论者自身的视野和手头的实现工具,而且几乎…
学好离散数学对深入学习编译原理来说是非常必要的基础。&br&&br&最典型的例子是图论。编译原理里充满了对图论的应用。无论是编译器的中间表示、寄存器分配,还是运行时支持系统中的GC之类,到处都是图。&br&&br&掌握了图论,在看到这种问题时就可以有清晰的思路去分析:&br&&ul&&li&&a href=&/question//answer/& class=&internal&&C# 是使用引用计数来发现垃圾对象的吗? - RednaxelaFX 的回答&/a&&br&&/li&&li&&a href=&/question/& class=&internal&&基于中间代码的优化中 循环的查找算法有哪些呢 循环的优化方法又有哪些? - 计算机专业&/a&&br&&/li&&li&&a href=&/question/& class=&internal&&如何设计三地址中间代码的数据结构,以便于基本块分析和代码优化? - 编译原理&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&编译器生成的汇编语句执行顺序为什么与C代码顺序不同? - RednaxelaFX 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&请教拓扑排序中的一点疑问? - RednaxelaFX 的回答&/a&&br&&/li&&li&…&/li&&/ul&&br&然后一些数学结构,例如格(lattice):&br&&ul&&li&&a href=&/question//answer/& class=&internal&&lattice theory 的经典著作以及它的应用有哪些? - RednaxelaFX 的回答&/a&&/li&&/ul&&br&自动机理论,在编译器的词法和语法分析器里得到大量应用:&br&&ul&&li&&a href=&/question/& class=&internal&&龙书3.9.5(第一版)DFA的状态转换表压缩方法是如何实现的? - 算法与数据结构&/a&&br&&/li&&li&&a href=&/question/& class=&internal&&如何从零写一个正则表达式引擎? - 编程&/a&&br&&/li&&li&…&/li&&/ul&&br&概率也可以算在离散数学里,&br&&ul&&li&&a href=&/question//answer/& class=&internal&&现在的编译器有没有利用统计与概率方面的算法来做优化? - RednaxelaFX 的回答&/a&&/li&&/ul&&br&太多实用的知识了嗯。
学好离散数学对深入学习编译原理来说是非常必要的基础。最典型的例子是图论。编译原理里充满了对图论的应用。无论是编译器的中间表示、寄存器分配,还是运行时支持系统中的GC之类,到处都是图。掌握了图论,在看到这种问题时就可以有清晰的思路去分析:
在今天,过虑了。&br&&br&在前前任公司开发大型C++框架,经历过 STL 被禁止 -& 调研测试 -& 解决问题 -& 定制开发推广使用的过程。&br&&br&Allocator多线程和长期运行后的内存碎片问题,tcmalloc (&a href=&///?target=https%3A///gperftools/gperftools& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&gperftools/gperftools · GitHub&i class=&icon-external&&&/i&&/a&) 解决得很好,越跑越慢甚至到后面分配不出内存的现象可以说是绝迹了。当然如果你在开发史上最昂贵但至今还在抓bug的战斗机(&a href=&///?target=https%3A///& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&/&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&),连动态分配内存都要禁止(&a href=&///?target=http%3A///JSF-AV-rules.pdf& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&/JSF-AV-r&/span&&span class=&invisible&&ules.pdf&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&),那另说。&br&&br&STL有大量动态分配是真的,有可能影响性能也是真的,但通常都是有针对性解决方法的,真不必因噎废食。上了tcmalloc我也还是遇上过内存分配大幅影响性能的情况,通常就是一些能很容易预知vector大致长度的地方,reserve一把立竿见影,当然这个不仅是内存分配问题了。另,用deque代替vector通常是过度(且错误的)优化,也是碎片内存大户,vector resize代价真没这么大。 again: 没跑过profile就去抓性能问题的都是扯。&br&&br&多线程环境下被STL容器玩死的案例多是多线程共享容器,对什么是mutable的没概念(没办法,对其他包括C语言背景的人来说,他就想安静地在字典里取个值 some_container[key] 竟然会mutate是有点毁三观),线上高压力死翘翘留下个莫名其妙的 core dump。由不了解而恐惧,由恐惧而成为禁忌。&br&&br&要说得禁用的坑的话,gcc到现在还是COW的std::string才是坑吧……(谢
&a data-hash=&1bb0c8bbed4& href=&///people/1bb0c8bbed4& class=&member_mention& data-tip=&p$b$1bb0c8bbed4&&@Wang Shuai&/a& gcc 5 已经不 cow 了)
在今天,过虑了。在前前任公司开发大型C++框架,经历过 STL 被禁止 -& 调研测试 -& 解决问题 -& 定制开发推广使用的过程。Allocator多线程和长期运行后的内存碎片问题,tcmalloc () 解决得很好,越跑越慢甚至到后面分配不出…
来看这个代码:&br&&div class=&highlight&&&pre&&code class=&language-text&&int fun(int& a)
return a+b+c;
int main()
//.........做一些和a无关的事
return fun(a);
&/code&&/pre&&/div&这个代码是很好优化的,因为编译器知道a的值是1,参考上下文,编译器又能知道b和c的值也是1,&br&而且根本没有人用到了a,b,c三个变量,也没有任何人在修改a,b,c三个的值,所以编译器可能就直接&br&把这个函数优化成:&br&&div class=&highlight&&&pre&&code class=&language-text&&int main() { return 3; }
&/code&&/pre&&/div&了.&br&&br&这么优化有什么问题吗? 单线程没问题,但多线程就有问题了,如果是多线程,&br&a的值虽然在当前上下文中不会被修改,但可能正在被其他线程修改啊.于是上面的优化&br&就不对了. 那么,volatile关键字在这里就可以帮助我们了,volatile关键字提醒编译器: &br&a可能随时被&b&意外&/b&修改.&br&意外的意思是虽然当前这段代码里看起来a不会变,但可能别的地方正在修改a的值哦.&br&所谓&别的地方&,某些情况下指的就是其他线程了.&br&&br&那么,如果把代码修改如下:&br&&div class=&highlight&&&pre&&code class=&language-text&&int fun(volatile int& a)
return a+b+c;
int main()
volatile int a=1;
//.........做一些和a无关的事
return fun(a);
&/code&&/pre&&/div&编译器就不敢优化了:&br&&br&&div class=&highlight&&&pre&&code class=&language-text&&int fun(volatile int& a)
int b = //这里从内存读一下a吧,谁知道a还等不等于1呢
int c = //这里再从内存读一下a吧,谁知道a还等不等于1呢
return a+b+c;
//这里也从内存读一下a吧,谁知道a还等不等于1呢
int main()
volatile int a=1;
//.........做一些和a无关的事
return fun(a); //完全不敢优化啊,鬼知道a变成多少了....
&/code&&/pre&&/div&&br&同理的,这段代码:&br&&div class=&highlight&&&pre&&code class=&language-text&&//..........
//做一些和a无关的事
if(a==0) doSomething();
//..........
&/code&&/pre&&/div&编译器会发现,a肯定等于0啊,那我还if个毛啊,直接优化掉!&br&&div class=&highlight&&&pre&&code class=&language-text&&//..........
//做一些和a无关的事
doSomething(); //if被去掉了
//..........
&/code&&/pre&&/div&但,一旦添加了volatile,编译器就不敢优化了.例如:&br&&div class=&highlight&&&pre&&code class=&language-text&&//..........
volatile int a=0;
//做一些和a无关的事
if(a==0) doSomething(); //可不敢优化这里! 谁知道a变成多少了!
//..........
&/code&&/pre&&/div&&br&这便是volatile的作用了.&br&&br&必须补充说明,volatile和锁没有一毛钱的关系,该加锁依然需要加锁.给变量添加volatile并不会让其自动拥有一个锁.所以该加锁还得加.&br&&br&//------------------- 更新答案 -------------------------------------------&br&&br&感谢大家的鼓励,受宠若惊! 重新看了一下答案,感觉还可以再补充一下,再举一个例子吧:&br&&br&网上教程里经常见到双检锁保证单例模式的代码,简化一下,大概逻辑如下:&br&&div class=&highlight&&&pre&&code class=&language-text&&static int*
int& get_instance()
if( !instance ) { //检查如果单例的指针是0
此处有某种锁; //则在此处上锁
if( !instance ) {
//再判断一次,以防等待锁期间有别的线程已经new完了
instance = //确认无误则new之
int main()
int& i = get_instance();
&/code&&/pre&&/div&&br&耳听为虚眼见为实,咱们看看反汇编如何(Intel ICC,O2,为了方便看反汇编禁用inline):&br&&div class=&highlight&&&pre&&code class=&language-text&&...................
eax,dword ptr ds:[010B5100h] //读取instance指针到eax
eax,eax //检查eax是否为0
get_instance+12h (010B1042h) //如果为0,则跳转下文010B1042处
...................
//此处为下文中跳回的位置
...................
//get_instance()函数返回
................... //010B1042从这里开始
dword ptr ds:[10B309Ch] //这里面call进去是malloc函数
esp,4 //调整栈
dword ptr ds:[010B5100h],eax//将malloc出的写回instance地址
get_instance+0Dh (010B103Dh) //跳回前面的代码
.........................
&/code&&/pre&&/div&&br&反汇编发现什么问题没? 喂! 判断只做了一次啊!!!! 第二个if去哪里了!&br&哪里去了? 被编译器优化掉了.... 因为这里的优化逻辑很简单:&br&如果第一个判断某值==0成功,根本没必要去做第二个判断,因为编译器能发现此值没被这段代码&br&修改,同时编译器认为此值也不会被其他人&意外&修改,于是,苦心积虑所做的双检锁失效了.跟没写一样.&br&&br&好了,见证奇迹的时候到了,我们就改一行代码:&br&&div class=&highlight&&&pre&&code class=&language-text&&static int*
&/code&&/pre&&/div&&br&再编译一下,看看反汇编:&br&&div class=&highlight&&&pre&&code class=&language-text&&
eax,dword ptr ds:[h]
//读取instance指针到eax
//检查eax是否为0
get_instance+17h (h)//如果为0,则跳转下文h处
.................
//get_instance()函数返回
.................
//以下为上文中跳转位置:
eax,dword ptr ds:[h] //再次读取instance指针到eax
//再次检查eax是否为0
get_instance+0Dh (0120103Dh) //如果非0,跳回上文return处
//如果还是0,往下执行malloc什么的.
dword ptr ds:[120309Ch] //这里进去是malloc
...........
dword ptr ds:[h],eax //将malloc好的值写回instance
get_instance+0Dh (0120103Dh) //返回上文
...........
&/code&&/pre&&/div&&br&终于,双检锁的逻辑正确了.因为volatile已经提示编译器,instance指针可能被&意外&修改.不要瞎做优化.&br&&br&这里有一个要吐槽的,intel ICC用最高等级优化,不加volatile的话连第一个判断都被优化掉了,&br&而MSVC无论怎么开优化,加不加volatile,永远两个判断全做,不愧是安全第一...&br&&br&特别提醒: 实际上即使加了volatile,这样的双检锁依然不安全,只有原子操作才安全,&br&详情请见我的另一个答案:&br&&a href=&/question//answer/& class=&internal&&对int变量赋值的操作是原子的吗? - 知乎用户的回答&/a&&br&&br&//------------------------------------&br&&br&评论区有朋友问是否多线程都要加volatile,首先,无论加不加volatile关键字,&br&任何多线程同时读/写变量,不加锁不用原子操作,则都是race condition,&br&在C++11标准中,race condition是未定义行为.这样做就跟*((int*)0)=1一样危险.&br&所以,上文中的双检锁依然是危险的.因为对instance本身的读写没有锁,且是非原子的.&br&&br&但是,回到现实中,很多锁或者大部分原子操作都附带memory read/write barrier, &br&一定程度上可以保证内存读写的顺序不会被编译器瞎优化.确实能避免一些危险.&br&至于memory barrier能不能就完全替代volatile了,基本可以确定是不能,但我水平有限,举不出例子.&br&&br&最后的最后归纳一下吧,多线程读写变量? 要安全? 加volatile! 加原子操作/锁!&br&&br&PS: 如果想转载请署我名且通知我,因为这样我会好爽好爽
来看这个代码:int fun(int& a)
return a+b+c;
int main()
//.........做一些和a无关的事
return fun(a);
}这个代码是很好优化的,因为编译器知道a的值是1,参考上下文,编译器又能知道b和c的值也是1,而且根本没有…
谢邀(终于用上这个高大上的词汇了,真的有点小激动呢)&br&&br&WTL都算不上什么Framework,就是利用泛型特性对Win API做了层封装,设计思路也没摆脱MFC的影响,实际上用泛型做UI Framework也只能算是一次行为艺术,这个思路下继续发展就会变得没法用了,比如 代码过于复杂,编译太慢,出错不好调试等问题难以解决。&br&而且封装得也不完全,还是随处可见 HWND HDC之类的东西。&br&用途主要是写一些很小的程序,或者作为其他UI框架的后端实现部分,比如我写过一个小框架用来做安装卸载程序,非常小,其中创建管理窗口部分是用WTL的。&br&&br&MFC是更高级点的Win API封装,比WTL封装彻底,很难见到HWND HDC了,也提供了不少实用工具类,比如高级控件,泛型容器,IO访问,网络协议等。除此之外,还提供了一些基本框架,比如 Document/View,这就是个MVC的简化版本,只有MV,但是对于数据的管理,消息的传递等又没有什么约束,导致Doc/View被用得乱七八糟。尤其是对事件处理的模型,消息映射是功能简陋,而且容易出错的方式,唯一优点是性能好。 从VC++ 1.X就有MFC了,那时整个UI界的设计思想都比较落后(除了Apple),MFC又背负了沉重的兼容性包袱,比如vc++ 1.52的MFC程序到了vc2003稍加修改都可以编译,导致MFC后期没有什么发展,就是沿着老的思路完善了些细节,添加了些组件,但是根本性的设计问题没有改进。&br&&br&GTK,这个吃了语言的亏,用C写面向对象实在是痛苦,虽然在思想上比MFC要先进了些,但是写出来的代码比MFC要罗嗦很多了。相比MFC,多了Layout的概念,事件处理上有了Signal/slot,虽然用起来很麻烦。&br&&br&wxWidgets,这个基本就是个跨平台的MFC,对各个平台的差异做了抽象,实际上后端大多还是用平台原生的API实现,好多控件都是直接用系统原生的。有wxWidgets for GTK+的版本,后端就是GTK+,wxWidgets就是一层壳。这也是wxWidgets的优点,它编译出来的程序发行包比较小,性能也不错。&br&&br&以上这些就是上世纪90年代的UI Framework技术水平了,至今它们也依然没有太多进步。&br&下面来谈谈21世纪的技术。&br&&br&Qt,虽然它也是上世纪90年代出现的,但是它在21世纪有了长足的进步。应该说它的起点就比较高,一开始就定位跨平台,而且不满足于简单封装系统API,而是要自己创造出一套完整的API和框架,甚至要代替系统API,所以不仅仅是做UI,而是涉及到了APP开发所用到的所有东西,包括网络,数据库,多媒体,脚本引擎等。signal/slot是Qt发明的,这是事件通知模型里C++语言的最佳实现了,甚至我都觉得这该写进C++标准,估计C++委员会的老顽固们是从不写GUI的。&br&早期的QT也是没有DirectUI的概念的,每一个QWidget都对应一个原生窗口,从Qt4.4开始,只有顶层QWidget才是原生窗口,而Child Widget是Alien Widget,只是个抽象的图层不对应原生窗口,这就实现了DirectUI的概念,很多图形效果也就变得可能了,比如窗口层叠透明效果。&br&在4.8后实现了QPA(Qt Platform Abstraction),这就使移植Qt变得很容易,目前Qt是支持平台最多的框架没有之一。&br&由于早期授权的问题,Qt对于开源社区不是很友好,导致推广不太顺利,直到它改成了LGPL方式,如果Qt能早点想开了,恐怕就没有wxWidgets的生存空间了。&br&Qt的缺点也是有的,就是太大,不过可以自己剪裁,我可以把QT库剪裁到发行包压缩后2.5MB。&br&&br&WPF,微软在Win Form的思路上走到死胡同后,终于痛下决心用正确的方法开发UI库了。21世纪的UI一定是定义出来的,绝对不能是代码写出来的,所以有了XAML这个强大的定义工具,不但可以定义UI布局,还包括图形动画效果,消息响应方式等。配合C#这种优秀的语言,更是如虎添翼。但是问题也很明显,就是过于庞大,不仅开发时要用到庞大的IDE和设计工具,发行的安装包也十分巨大,所以目前还是很少有人拿他写通用软件客户端的,大多是做企业项目时写专用客户端。&br&大概4-5年前吧疼讯曾经用WPF写了个QQ,但是只实现了基本功能就已经比C++客户端大好多了,而且运行缓慢,主要是太吃内存,而且那时WPF的优化还不充分。&br&&br&最后我想补充下真正的UI库之王,cocoa。&br&Apple的成功有很多原因,其中之一就是cocoa,cocoa理念十分先进,而且出来得早,我都怀疑Qt和WPF有不少思想都是借鉴cocoa的。&br&定义式的UI,用xib就可以定义UI的绝大部分细节,而且提供所见即所得的可视化设计工具。&br&严格的MVC,而且定义非常清晰,分工明确。&br&signal/slot,虽然不叫这个名字,但思想就是,而且真的是拖动鼠标就能connect。&br&提供了ARC,闭包和反射,给UI开发带来巨大的便利性,当然这得益于Objective-C这个语言。&br&&br&再补充下 Borland的OWL和VCL。&br&我是从Borland C++3.0和Delphi 1.0开始用的,那时的Borland看来很有前途的,可惜后来一系列决策失误导致现在这个公司几乎消失了,同学们不要再往这个坑里跳了。&br&OWL曾经和MFC是竞争对手,设计思想也差不多,个人感觉OWL的API设计更优雅一点,但是在市场上OWL被MFC彻底击败。&br&Delphi是神作,它在RAD(快速应用开发)领域长时间没有对手,直到BS架构取代CS架构。Delphi的特点就是简单、开发快,单纯就写个基本可用的应用来说,可能至今都没有比他更快的,但是缺点就是丑,基本大多数Delphi应用都是一大堆控件堆积在一起,很不美观,另外由于Pascal语言的限制无法和现有大量的C/C++代码融合。虽然后来有C++ Builder,但是Builder里简单和快的优点也消失了。Borland的C++编译器越做越差,导致后来开源项目都不太愿意兼容这个编译器了。&br&VCL准确地说不是UI库,而是一套组件接口规范,类似COM ActiveX。delphi和C++builder都是基于这个规范构建了基础库。&br&&br&UI库是个很大的话题,够写好几本书来探讨的,我这里就是随便写点自己的感受。&br&单纯讨论每个库的优劣是没有意义的,而是要放到具体的应用场景里来看,每个库都有自己擅长的场景。&br&&br&如果仅在Windows下,追求程序小巧,用WTL,不足的地方自己实现去吧,但是视觉效果就呵呵了。&br&如果可以大一点,还要好看点,那就Qt。&br&如果完全不在乎大小,只要视觉效果华丽,就用WPF,如果把开发工具价格也考虑进来,那么土豪才会选WPF呢。&br&MFC就是个鸡肋了,除非你现有的工程师不会用别的,或者有历史遗留代码要保持兼容。&br&&br&如果要求跨平台,那么就用Qt,wxWidgets和GTK+跟现在的Qt比起来没有什么优势了。&br&&br&如果是iOS Android,那么最好用原生UI库,除非你写游戏。
谢邀(终于用上这个高大上的词汇了,真的有点小激动呢)WTL都算不上什么Framework,就是利用泛型特性对Win API做了层封装,设计思路也没摆脱MFC的影响,实际上用泛型做UI Framework也只能算是一次行为艺术,这个思路下继续发展就会变得没法用了,比如 代码…
浏览了以上所有人的答案,结合我平常在项目中的实际经验,谈谈我们团队的Python部署与发布流程。&br&目前很多公司还是用着&b&石器时代&/b&的部署方式,怎么做呢?&br&&br&&div class=&highlight&&&pre&&code class=&language-text&&1. 本地写代码,可能还没有virtualenv环境,是的其实我的老东家就是这样的。
2. 写一个脚本,安装需要的依赖到系统global环境,比如说 MySQLdb,
可能还要用apt-get 或者 yum 安装 python-dev 等等系统依赖,然后用pip 安装Python依赖。
3. 提交到svn/git,然后在测试机器上拉代码下来,运行脚本安装完依赖后,
如果是一个web项目,那么可能会直接 python web.py 8080 测试一下会不会报错,
测试完几个接口发现没问题,关掉测试机器。
4. 在生产环境把代码拉下来,或者通过部署系统,这里的部署系统一般是一个web页面,
能够将svn/git 上的代码打包后执行某一个脚本,来完成相应的部署,
也有可能是直接在机器上执行:
nohup python /path/to/python/main.py 2&1 & /dev/null &
就启动来这个进程,然后自己可能还有一些业务监控来定时的监控这个脚本的存活状态。
5. 这里可能nginx已经配置好,你发布的是一个Django应用,那么打开浏览器,
查看网页无误。
&/code&&/pre&&/div&&br&ok,大功告成,我已经是一位合格的工程师了,我所理解的Python发布或者所有的发布不都是这样么,&b&大家都是这样的&/b&。&br&如果你躺枪了,很好,我喜欢。&br&让我们看看这里的步骤缺少什么,我不仅仅从发布部署来说,我们谈谈一个&b&理想的开发测试部署流程应该是怎样的。&/b&&br&
1. 你应该有一个与线上环境一模一样的测试/开发机器,这里说的是系统环境而不是物理环境,比如说内核版本,Python版本,libc 版本,gcc 版本,shell 的环境等等都应该跟线上环境一样,这是保证代码质量的第一关,或许不应该叫做代码质量而是工程质量。有人可能会用eclipse或者其他的云云开发IDE,OK,没问题,保证系统是一样的,这里有点难。&br&
2. 你应该有一个virtualenv环境,因为你的开发机器可能有多个项目,而且可能因为有些依赖版本问题,导致你发现不同的项目可能对同一个模块有不同版本的依赖,那么请你准备一个virtualenv环境,这是Python开发人员必备的。&br&
3. 你应该把代码提交到git, 但是提交之前,你应该运行一般单元测试,单元测试包含两个部分,一是对整个项目里的所有代码有一个代码静态检查,例如pylint和pep8,第二部分是自动运行你的测试用例,因为你的一个小改动可能会影响到其他模块,而这一点你开发的时候没有意识到或者说你影响的模块不是你写的,这一点会让你写的代码更健壮,同时你更有信心对现有代码做新需求开发或者变动,这里,你可以把你的测试用例启动脚本活着命令加到git hook,这样每次commit的时候都会启动测试程序。&br&
4. OK,保证测试用例通过后,你应该对这次写的代码很有信心了,那接下来就是把代码发布到测试环境。怎么做呢?&br&&br&一个起码看起来合格的Python项目,大体上代码构建的目录应该是下面这样的,请参考《以正确的方式开源Python项目》 &a href=&///?target=http%3A//www.oschina.net/translate/open-sourcing-a-python-project-the-right-way& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&oschina.net/translate/o&/span&&span class=&invisible&&pen-sourcing-a-python-project-the-right-way&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&br&所有的代码文件都在pro中,其他都是项目发布于部署使用到的&br&&div class=&highlight&&&pre&&code class=&language-text&&-rwxr-xr-x 8 root root 4096 Sep 16 22:06 .git/
-rw-r--r-- 1 root root
434 Aug 10 16:00 .gitignore
-rw-r--r-- 1 root root
166 Jul 26 11:49 AUTHORS.md
-rw-r--r-- 1 root root
149 Aug 10 16:49 AUTHORS.rst
-rw-r--r-- 1 root root
0 Aug 10 16:49 CONTRIBUTING.rst
-rw-r--r-- 1 root root
245 Jul 26 11:59 HISTORY.md
-rw-r--r-- 1 root root
100 Aug 10 16:49 HISTORY.rst
-rw-r--r-- 1 root root 1453 Aug 10 16:49 LICENSE
-rw-r--r-- 1 root root
221 Aug 10 16:49 MANIFEST.in
-rw-r--r-- 1 root root 2964 Sep 12 11:19 Makefile
-rw-r--r-- 1 root root
239 Jul 26 11:49 README.md
-rw-r--r-- 1 root root
161 Aug 10 16:49 README.rst
drwxr-xr-x 2 root root 4096 Sep 16 22:06 conf/
drwxr-xr-x 2 root root 4096 Jul 26 11:59 deb-scripts/
drwxr-xr-x 2 root root 4096 Aug 23 15:52 doc/
drwxr-xr-x 8 root root 4096 Jan 16 13:12 pro/
-rw-r--r-- 1 root root
67 Aug 10 16:49 requirements-dev.txt
-rw-r--r-- 1 root root
2 15:34 requirements.txt
-rw-r--r-- 1 root root
22 Aug 10 16:49 setup.cfg
-rwxr-xr-x 1 root root 1406 Aug 10 16:49 setup.py*
drwxr-xr-x 4 root root 4096 Sep
2 17:30 utils/
&/code&&/pre&&/div&我来解释一下这里的几个主要文件的作用. 这里的目录结构可能也跟我们团队的命名习惯有关.&br&&div class=&highlight&&&pre&&code class=&language-text&&conf/
conf/api.conf
// 项目配置
conf/logrotate.conf
// 日志轮转配置
conf/uwsgi.ini
// uwsgi 配置
conf/pro.upstart
// upstart 文件
conf/paste.ini
// paste 是用来部署uwsgi的一个中间件
conf/pro.cron
// 这里是crontab配置
// 其他配置,可能是允许执行的sudo命令等
&/code&&/pre&&/div&deb-scripts/ 包含三个文件,这里我们说debian系统打包,Redhat 打 rpm 也同理。&br&&div class=&highlight&&&pre&&code class=&language-text&&eb-scripts/before-remove.sh
// 卸载前执行的脚本
deb-scripts/before-install.sh
// 安装前执行的脚本
deb-scripts/after-install.sh
// 安装后执行的脚本
&/code&&/pre&&/div&&br&doc/ 应该是项目的文档,这里推荐用sphinx 生成文档或者你自己写markdown也可以。&br&&br&utils/ 下面包含了你可能需要用到的启动依赖,但是又不想每次都远程下载,且不是Python本身的依赖而是环境依赖,好吧,我们在utils下面放了一个virtualenv,执行virtualenv 就可以在本地生成一个virtualenv 环境了, 还有打包deb的脚本&br&&br&Makefile 文件包含了很多命令,比如:&br&&div class=&highlight&&&pre&&code class=&language-text&&make test
// 执行单元测试和静态检查
// 执行 pylint
// 执行pep8 检查
&/code&&/pre&&/div&一系列你经常用到的功能,都可以放到Makefile&br&&br&2. 你应该把你的代码打成一个安装包,而不是一个压缩包,因为你要发布的是一个服务而不是一个模块,那么请你打成deb或者rpm包。&br&让我们看下打包代码:&br&&div class=&highlight&&&pre&&code class=&language-text&&#!/bin/sh
... // 省略了变量部分
if [ ! -d wheelhouse ]; then
make wheel
fpm -t deb -s dir -n &$PKG_NAME& -v &$VERSION& --prefix &$DEST_DIR& -f \
--depends make \
-x '*__pycache__' \
-x '*.pyc' \
-x '*.pyo' \
-x '*.deb' \
--before-install deb-scripts/before-install.sh \
--after-install deb-scripts/after-install.sh \
--before-remove deb-scripts/before-remove.sh \
Makefile HISTORY.rst LICENSE AUTHORS.rst CONTRIBUTING.rst setup.cfg \
MANIFEST.in README.rst setup.py utils requirements-dev.txt requirements.txt wheelhouse conf \
$PYTHON_MODULES
&/code&&/pre&&/div&&br&一目了然,我们会把依赖打到 wheelhouse 里面,然后把 wheelhouse 一同打包到 deb 包,这里使用了 fpm 这个打包工具,需要安装ruby gem 来安装。&br&然后在你的 make install 命令可以包含下面这个:&br&&div class=&highlight&&&pre&&code class=&language-text&&pip install --use-wheel --no-index --find-links=wheelhouse -r requirement.txt
&/code&&/pre&&/div&在你的 deb-scirpt/after-install.sh 里面,这个脚本会在deb包安装完成后执行,你应该在这里完成你的环境依赖安装还有你配置文件的加载,crontab的配置等,一个简单的脚本应该像下面这样:&br&&br&&div class=&highlight&&&pre&&code class=&language-text&&#!/bin/sh
PREFIX=${PREFIX:-/opt/pro}
REPODIR=${REPODIR:-/data2/pro}
LOGDIR=${LOGDIR:-/data2/log/pro}
IMAGE_CACHE=${IMAGE_CACHE:-/data2/image/cache}
RUN_AS_USER=www-data
mkdir -p $REPODIR
mkdir -p $LOGDIR
mkdir -p $IMAGE_CACHE
chown -R &$RUN_AS_USER&:&$RUN_AS_USER& $REPODIR
chown -R &$RUN_AS_USER&:&$RUN_AS_USER& $LOGDIR
chown -R &$RUN_AS_USER&:&$RUN_AS_USER& $IMAGE_CACHE
cd &$PREFIX&
# this project does not require install.
# make bootstrap install
make bootstrap
# install crontab, upstart job, logrotate config etc
install conf/pro.upstart /etc/init/pro.conf
install conf/logrotate.conf /etc/logrotate.d/pro
install -o root -m 0440 conf/pro /etc/sudoers.d/pro
install -o root -m 0644 conf/pro.cron /etc/cron.d/pro
start pro || true
&/code&&/pre&&/div&3. 最后一步就是 start pro&br&这里使用upstart启动你的应用,你应该把你的应用交给系统而不是你自己&br&所以在 after-install 中,你需要把pro.conf这个文件安装到 upstart 目录.&br&4. 以上的所有步骤,还在你的本地,你需要做的是把代码发布到生产环境。这里你需要把你的deb包上传到私有apt源,然后就是发布到正式环境了。&br&5. 发布有几种方式:&br&&div class=&highlight&&&pre&&code class=&language-text&&1. 在机器上直接执行 apt-get install pro(不推荐)
2. 利用fabric执行远程命令发布(次不推荐)
3. 利用puppet发布(推荐)
&/code&&/pre&&/div&前两者无需多说,利用puppet发布,可以使你的发布更佳规范,同时也可以对配置做更规范的管理,一些系统依赖,不是Python的而是系统本身的,比如有时候出现libpcre 这样的二进制系统依赖的时候,你应该利用puppet安装这些依赖,而不是手动去执行安装, 具体的 puppet 相关就不细说了。&br&&br&OK,以上是个人比较推荐的Python流程,有错误请指正。
浏览了以上所有人的答案,结合我平常在项目中的实际经验,谈谈我们团队的Python部署与发布流程。目前很多公司还是用着石器时代的部署方式,怎么做呢?1. 本地写代码,可能还没有virtualenv环境,是的其实我的老东家就是这样的。
2. 写一个脚本,安装需要的…
&b&什么叫arm,什么叫单片机?&br&学嵌入式,不在于你会多少芯片,而更重要的是嵌入式程序设计思路,编程方法。比如循环队列,循环缓冲区等。如何接收中断程序效率最高?&/b&&br&&b&-----------------------------------------------------&/b&&br&&b&第一次赞的数量超过3个,更新一下答案庆祝一下。&/b&&br&&b&其实51单片机系列和ARM系列,只是一个工具。要根据实际的项目去选择。当然,会的芯片越多,上手其他的更容易。但是我觉得,重点还在于嵌入式软件的编程思想。比如函数代码和变量的可移植性,如何定义变量,尽量不要使用全局变量,如何更有效的记录日志等等。推荐基本书吧。林锐的《高质量程序设计》,&/b&&br&《&a href=&///?target=http%3A///link%3Furl%3D4kZCAq87BmnGJcjYDZnn7v5YqsRtkJPk2EXtknSvbJrOTNXFw0AY6JNSFoW6T9WYrG7nm9JwBGnYZWR9xkalA_& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&时间触发嵌入式系统设计模式&i class=&icon-external&&&/i&&/a&》。广告时间:还有我的个人博客&a href=&///?target=http%3A//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&大头资讯网 | 大头大头,下雨不愁&i class=&icon-external&&&/i&&/a&。&br&自己的认识也都只是皮毛,欢迎多多交流。&br&学会裸机编程之后,再学习一下Linux和ucos等操作系统也是必要的。&br&&b&-----------------------------------------------------&/b&&br&&b& 哇塞,赞的数量已经到达15个,整个人都不太好了,再更新一下答案庆祝一下。&/b&&br&&b&如果是学习arm的话,ucos嵌入式操作系统是必须要学习一下的。而且它的代码开源,想要学习操作系统原理的同学,还是可以分析一下代码的。教材的话,可以看看这本书。&/b&&br&《嵌入式实时操作系统UC/OS-11原理及应用》&br&学会了ucos,怎么能不顺便学习一下Linux呢。Linux的多线程调度,线程进程间通信等等,推荐一个开源代码,mjpg-streamer,可以折腾一下,可以获取USB摄像头的数据,然后通过网页等途径访问摄像头。这个代码设计的也很不错,学习Linux的同学可以看一下。&br&&b&-----------------------------------------------------&/b&&br&&b&已经到47个赞了,答主已经疯了。&/b&&br&&b&对的,还有数据结构也是很重要的,比如如何自己使用C语言实现一个队列?&/b&&br&&b&-----------------------------------------------------&/b&&br&&b&看着已经109个赞,答主已经晕过去好几回了&/b&&br&&b&最近再搞嵌入式的程序,使用的是STM32,纯裸机编程。越来越明白一个好的架构的重要性了。所以想近期看一下ucosii的内核源码,学习一下架构设计相关的知识。比如说,如果写一个命令行AT指令解析的程序,应该如何编写呢,如何设计架构才更有利于后面指令的扩展呢?技巧性的东西真的是博大精深。正在慢慢的爬行在这无边无际的海洋中。自己以为到了大海,其实,只是一个臭水沟罢了。路还很长。。。。。。。。&/b&&br&&b&------------------------------------------------------&/b&&br&&b&好多赞了呀,再更新一下答案吧。&/b&&br&
如何学习嵌入式软件开发呢?这个问题好从自己大学说起。记得大二的时候接触51单片机,感觉这个东西使用起来好费劲,还设置各种寄存器,配置各种参数。当有一本书出现的时候,我豁然开朗了。这本书的名字叫《嵌入式软件程序设计,使用MCS-51》。这本书上介绍了很多我们常用到的一些单片机的功能和外设的控制。我需要使用单片机实现一个什么样子的功能,只需要找出相关代码,组合一下就OK了。so easy!
单片机的路,就这么慢慢走着。比如控制步进电机、直流电机、舵机等。如何控制超声波测距、温度传感器等。这种设备的代码都是烂大街的,一抓一大把。
顺便说一下,玩转嵌入式之前,C语言还是必须要搞定的。通过了计算机二级考试,可并不能证明你C语言合格。小平同志说过,实践是检验真理的唯一标准。多练手吧。《杜拉拉升职记》中也有一句话说的很正确,你能从书本上获得10%的经验,能够从前辈身上获得20%的经验,剩下的70%的经验都是从实践中得来的。
后面开始接触STM32和Atmel的一款ARM7芯片,一对比才发现,STM32的例程好丰富,各种都给你写好了,又和学51单片机一样,找到了诀窍了。瞬间就可以搞定各种功能,实现各种小玩意。大四的时候也参加了《CCTV机器人大赛》。
上了研究生之后,开始学习Linux,也不是自己想学,单纯是为了实验室项目的需要才不得不接触Linux,后面研究生也主要是在用Linux。期间也使用STM32做过一些项目。在这期间才学会了使用循环缓冲区的方式处理串口数据。此时,才真正静下心来思考,如何才能设计一个比较好的嵌入式软件架构。在代码编写中,也逐渐开始使用队列等结构。
有一次找工作面试,被面试官问到函数指针的用法,才把注意力放在函数的指针上。PS:函数指针和指针函数有啥区别呢。 &br&------未完待续-----&br&-----------------------------------------------------------------&br&&b&不知不觉,已经250+个赞了,被拉来更新一下。&/b&&br&还是那句话,&b&不是说底层不重要,而是不能把所有经历都放在会多少个芯片上。&/b&别人问你的I2C的时候,是问你的协议,而不是说你用过哪些芯片的I2C。最近在创业公司写一个系统,代码量已经到达80K(不要吐槽代码量不大,因为功能有限,又不是做一个火箭),基本功能就是GPS定位,GPRS数据通信,三轴检测等等。使用的外设都是基本的外设,串口、AD、中断等等。业务逻辑是一个重点,GPS和GSM模块的驱动也是另一个重点,还有一个比较重要的是低功耗方面。&br&在编程方面可以借鉴的地方罗列一下,仅供参考。&br&1、添加了一个终端串口打印函数,对printf进行重新封装,可以直接打印时间,打印信息的分类和打印内容,便于通过标志位选择性的输出你所需要的打印信息。&br&2、添加了AT指令的调试接口,可以通过串口终端发送AT指令获取系统的各个参数和变量的状态,并且可以出发某些事件,便于调试和查找问题。这些在系统正式上线的时候砍掉即可。&br&-------------先写到这里---------------&br&600+个赞了。每次填写都有新的感悟。先把自己的微信号放在这里,互相交流,互相学习。&br&&img src=&/185f5adae7a419a0fd2498_b.jpg& data-rawwidth=&713& data-rawheight=&689& class=&origin_image zh-lightbox-thumb& width=&713& data-original=&/185f5adae7a419a0fd2498_r.jpg&&
什么叫arm,什么叫单片机?学嵌入式,不在于你会多少芯片,而更重要的是嵌入式程序设计思路,编程方法。比如循环队列,循环缓冲区等。如何接收中断程序效率最高?-----------------------------------------------------第一次赞的数量超过3个,更新一下答…
这种功能可以有很多不同的叫法,但其本质都是搜索一个语法元素(例如一个变量名)所代表的实体(例如一个变量)的所有被引用的地方(occurrences / references)。&br&&br&这种功能的实现要点有这么几个:parser、AST、符号表。&br&&ul&&li&IDE要有一个语法分析器(parser),能够把输入的源码分析(parse)为一棵抽象语法树(AST),并将AST里出现的符号及其所引用的实体之间的对应关系记录在一种叫做符号表(symbol table)的数据结构里。这个动作既可以事先批量进行,也可以在用户编辑的同时增量式进行——有没有觉得有时候IDE里各种提示过了一小会儿才出现?这背后就很可能是增量式分析在进行中。Eclipse的增量式语法分析在这个文档里有提到:&a href=&///?target=https%3A//wiki.eclipse.org/FAQ_How_do_I_use_a_model_reconciler%253F& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&FAQ How do I use a model reconciler?&i class=&icon-external&&&/i&&/a&&/li&&li&用户在编辑器中选中一段文本时,IDE要可以找出这段文本对应的AST节点,并且通过符号表找到它所对应的实体。例如从一个简单标识符找到它对应的局部变量声明。&/li&&li&接下来,在给定的AST范围内(例如说一个方法内),找出所有其它引用同一实体的AST节点。&/li&&li&最后在编辑器里对找到的这些节点进行高亮。&/li&&/ul&&br&Visual Studio代码不开源所以不方便用来讨论实现。&br&在IntelliJ里,这个功能叫做“Highlight Usages”:&a href=&///?target=https%3A///idea/help/highlighting-usages.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&IntelliJ IDEA 15.0
Highlighting Usages&i class=&icon-external&&&/i&&/a&&br&拿开源的Eclipse的Java Development Tools(JDT)为例。这个功能在Eclipse JDT里叫做“mark occurrences”:&a href=&///?target=http%3A//help.eclipse.org/luna/topic/org.eclipse.jdt.doc.user/tips/jdt_tips.html%23mark_occurrences& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Mark occurrences - Tips and Tricks (JDT)&i class=&icon-external&&&/i&&/a&&br&&br&这个功能的实现可以从下面的链接开始跟踪:&br&&a href=&///?target=https%3A///eclipse/eclipse.jdt.ui/blob/master/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java%23L1207& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&windowActivated() - eclipse.jdt.ui/JavaEditor.java at master · eclipse/eclipse.jdt.ui · GitHub&i class=&icon-external&&&/i&&/a&&br&&a href=&///?target=https%3A///eclipse/eclipse.jdt.ui/blob/master/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java%23L3260& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&updateOccurrenceAnnotations() - eclipse.jdt.ui/JavaEditor.java at master · eclipse/eclipse.jdt.ui · GitHub&i class=&icon-external&&&/i&&/a&&br&为举例方便,来详细看看其中在&a href=&///?target=https%3A///eclipse/eclipse.jdt.ui/blob/master/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java%23L3320& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&第3320行&i class=&icon-external&&&/i&&/a&的一段:&br&&div class=&highlight&&&pre&&code class=&language-java&&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&locations&/span& &span class=&o&&==&/span& &span class=&kc&&null&/span& &span class=&o&&&&&/span& &span class=&n&&selectedNode&/span& &span class=&k&&instanceof&/span& &span class=&n&&Name&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&IBinding&/span& &span class=&n&&binding&/span&&span class=&o&&=&/span& &span class=&o&&((&/span&&span class=&n&&Name&/span&&span class=&o&&)&/span&&span class=&n&&selectedNode&/span&&span class=&o&&).&/span&&span class=&na&&resolveBinding&/span&&span class=&o&&();&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&binding&/span& &span class=&o&&!=&/span& &span class=&kc&&null&/span& &span class=&o&&&&&/span& &span class=&n&&markOccurrencesOfType&/span&&span class=&o&&(&/span&&span class=&n&&binding&/span&&span class=&o&&))&/span& &span class=&o&&{&/span&
&span class=&n&&OccurrencesFinder&/span& &span class=&n&&finder&/span&&span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&n&&OccurrencesFinder&/span&&span class=&o&&();&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&finder&/span&&span class=&o&&.&/span&&span class=&na&&initialize&/span&&span class=&o&&(&/span&&span class=&n&&astRoot&/span&&span class=&o&&,&/span& &span class=&n&&selectedNode&/span&&span class=&o&&)&/span& &span class=&o&&==&/span& &span class=&kc&&null&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&locations&/span&&span class=&o&&=&/span& &span class=&n&&finder&/span&&span class=&o&&.&/span&&span class=&na&&getOccurrences&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&可以看到,假如在编译器中被选定的AST节点是一个“名字”(例如说标识符),那么接下来要做的事情就是:&br&&ol&&li&通过符号表找出这个标识符所引用的实体是什么,这段代码里就是resolveBinding()(追踪实现可以到&a href=&///?target=https%3A///eclipse/eclipse.jdt.core/blob/master/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java%23L1264& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&DefaultBindingResolver.resolveName()&i class=&icon-external&&&/i&&/a&),得到一个&a href=&///?target=http%3A//help.eclipse.org/mars/index.jsp%3Ftopic%3D%252Forg.eclipse.jdt.doc.isv%252Freference%252Fapi%252Forg%252Feclipse%252Fjdt%252Fcore%252Fdom%252FIBinding.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&IBinding&i class=&icon-external&&&/i&&/a&。&/li&&li&在给定的AST范围内,找出这个实体被引用的所有位置(occurrences)。&/li&&li&在编辑器里把找出来的位置设上高亮。&/li&&/ol&&br&渔就给这么多,接下来题主可以自己探索下去啦~&br&&br&=============================================&br&&br&题主说了“例如VS”,所以这里的回答假定题主想知道的是高质量的“找出引用”功能。&br&如果不要求质量很高,也有更简单的做法。补充个例子说明啥叫质量高。&br&&br&假如有这样的Java代码:&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&class&/span& &span class=&nc&&Foo&/span& &span class=&o&&{&/span&
&span class=&kt&&int&/span& &span class=&nf&&bar&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&c1&&// method name &bar&&/span&
&span class=&kt&&int&/span& &span class=&n&&bar&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&o&&;&/span&
&span class=&c1&&// local variable &bar& 1&/span&
&span class=&o&&{&/span&
&span class=&kt&&int&/span& &span class=&n&&bar&/span& &span class=&o&&=&/span& &span class=&mi&&2&/span&&span class=&o&&;&/span&
&span class=&c1&&// local variable &bar& 2&/span&
&span class=&kt&&int&/span& &span class=&n&&baz&/span& &span class=&o&&=&/span& &span class=&n&&bar&/span& &span class=&o&&+&/span& &span class=&mi&&1&/span&&span class=&o&&;&/span&
&span class=&c1&&// local variable &bar& 2&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&n&&bar&/span&&span class=&o&&;&/span&
&span class=&c1&&// local variable &bar& 1&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&这段代码里一共出现了5次“bar”标识符,但其实背后是3个不同的符号:&br&&ul&&li&方法&bar&&br&&/li&&li&局部变量&bar& 1&/li&&li&局部变量&bar& 2&br&&/li&&/ul&按照前面说的方法做分析的话,这里会得到如下的抽象语法树:(仅为讲解而写的简单例子)&br&&div class=&highlight&&&pre&&code class=&language-text&&ClassDeclaration &Foo&
- MemberList
- MethodDeclaration &bar&
- signature &()I&
- methodBody
- StatementOrDeclarationList
- VariableDeclaration &bar& // 1
- initializer
- ConstantExpression 1
- BlockStatement
- VariableDeclaration &bar& // 2
- initializer
- ConstantExpression 2
- VariableDeclaration &baz&
- initializer
- BinaryExpression
- VariableReference &bar& // 2
- ConstantExpression 1
- ReturnStatement
- VariableReference &bar& // 1
&/code&&/pre&&/div&可以看到,通过语法分析,构造出来的AST足以区分5次&bar&出现的地方各自代表的意义。所以,例如选定baz的初始化表达式中的bar时,就只有局部变量&bar& 2会被高亮,而另外两个&bar&实体都不会被高亮。&br&&br&而比较简单但低质量的做法就是从头到尾都只做词法分析——只将输入的源码切分为一个个单词。&br&这样做就会把本例子的5个&bar&都识别为同一个实体,标识的精度就变差了。&br&&br&换个更简单的例子再体会一下:&br&&div class=&highlight&&&pre&&code class=&language-java&&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&setFoo&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&foo&/span&&span class=&o&&)&/span& &span class=&o&&{&/span& &span class=&c1&&// parameter &foo&&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&foo&/span& &span class=&o&&=&/span& &span class=&n&&foo&/span&&span class=&o&&;&/span&
&span class=&c1&&// field &foo& / paramater &foo&&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&同样,做足语法分析就能区分this.foo与foo,而只做词法分析就会只能把它们看为同一实体。
这种功能可以有很多不同的叫法,但其本质都是搜索一个语法元素(例如一个变量名)所代表的实体(例如一个变量)的所有被引用的地方(occurrences / references)。这种功能的实现要点有这么几个:parser、AST、符号表。IDE要有一个语法分析器(parser),能…
已有帐号?
无法登录?
社交帐号登录
129 个回答
5467 人关注
256 个回答
530 人关注
8977 人关注
732 个回答

我要回帖

更多关于 turboc2 的文章

 

随机推荐