-
Oracle数据库完整性的五个约束条件是什么。和第二题一样五个约束条件: 非空、唯一、主码、外码、检查。 (1) not null(非空)约束 (2) unique(惟一)约束 (3) primary key(主键)约束 (4) foreign key(外键)约束 (5) check(校验)约束什么是存储过程,它的优点有哪些。 在Oracle过程中,我们可以自定义子程序,这种程序块被称为存储过程,存放在数据字典中,可以在不同的用户和应用程序之间共享,并可实现对程序的优化和重组, 优点: 存储过程在服务端,执行速度快 存储过程在第一次被执行后就常驻在高速缓存中,后续可以直接调用,从而提高了系统性能 丰富权限管理手段,提高数据库的安全性 可自动完成所需要先执行的任务,方便用户的使用请利用LOOP循环语句编写程序,求解10的阶乘。SQl>set serveroutput on;SQL>DECLAREN number:=1;count1 number:=2;BEGIN LOOP n:=n*count1;count1:=count1+1; IF count1>10 THEN EXIT; END IF; END LOOP; DBMS_OUTPUT.PUT_LINE(’10的阶乘为:’ || to_char(n));END; 创建一个函数,用于统计学生表(XSB)中不同性别的人数。SQL>CREATE OR REPLACE FUNCTION count_num(in_sex IN char) RETURN numberAS out_num number;BEGIN IF in_sex=‘男’ THEN SELECT COUNT(*) INTO out_num FROM XSB WHERE xb=‘男’; ELSE SELECT COUNT(*) INTO out_num FROM XSB WHERE xb=‘女’; END IF ; RETURN(out_num);END; SQL的基本运算符,常用运算符功能,单行运算符,多行运算符,in like含义,逻辑运算符。SQL基本数据类型: 1、字符型: varchar2(可变长度),char(定长字符串),long(变长字符串) 2、数字型: Number(p,s),Int(eger)十进制整型, float(二进制) 3、日期型: date (精确到秒)Timestamp(精确到秒后六位)
-
AND 和 OR 运算符AND 和 OR 可在 WHERE 子语句中把两个或多个条件结合起来。如果第一个条件和第二个条件都成立,则 AND 运算符显示一条记录。如果第一个条件和第二个条件中只要有一个成立,则 OR 运算符显示一条记录。原始的表 (用在例子中的):LastNameFirstNameAddressCityAdamsJohnOxford StreetLondonBushGeorgeFifth AvenueNew YorkCarterThomasChangan StreetBeijingCarterWilliamXuanwumen 10BeijingAND 运算符实例使用 AND 来显示所有姓为 "Carter" 并且名为 "Thomas" 的人:SELECT * FROM Persons WHERE FirstName='Thomas' AND LastName='Carter'结果:LastNameFirstNameAddressCityCarterThomasChangan StreetBeijingOR 运算符实例使用 OR 来显示所有姓为 "Carter" 或者名为 "Thomas" 的人:SELECT * FROM Persons WHERE firstname='Thomas' OR lastname='Carter'结果:LastNameFirstNameAddressCityCarterThomasChangan StreetBeijingCarterWilliamXuanwumen 10Beijing结合 AND 和 OR 运算符我们也可以把 AND 和 OR 结合起来(使用圆括号来组成复杂的表达式):SELECT * FROM Persons WHERE (FirstName='Thomas' OR FirstName='William')AND LastName='Carter'结果:LastNameFirstNameAddressCityCarterThomasChangan StreetBeijingCarterWilliamXuanwumen 10Beijing
-
概述在实际的业务场景应用中,我们经常要根据业务条件获取并筛选出我们的目标数据。这个过程我们称之为数据查询的过滤。而过滤过程使用的各种条件(比如日期时间、用户、状态)是我们获取精准数据的必要步骤,关系运算关系运算就是where语句后跟上一个或者n个条件,满足where后面条件的数据会被返回,反之不满足的就会被过滤掉。operators指的是运算符 ,有如下几种情况:运算符说明=等于<> 或者 !=不等于>大于>=大于等于<小于<=小于等于关系运算基本的语法格式如下 select cname1,cname2,... from tname where cname operators cval等于=查询出 列和后面的值严格相等的数据,非值类型的需要对后面值加上引号,值类型的不需要。语法格式如下:select cname1,cname2,... from tname where cname = cval;mysql> select * from user2; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | +----+-------+-----+----------+-----+ 3 rows in set mysql> select * from user2 where name='helen'; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 2 | helen | 20 | quanzhou | 0 | +----+-------+-----+----------+-----+ 1 row in set mysql> select * from user2 where age=21; +----+-------+-----+---------+-----+ | id | name | age | address | sex | +----+-------+-----+---------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 3 | sol | 21 | xiamen | 0 | +----+-------+-----+---------+-----+ 2 rows in set不等于(<>、!=)不等于有两种写法,一种是<>,另一种是!=,意思一样,可随意切换使用,但是 <> 先于 != 出现,所以看很多以前的例子,<> 出现频率比较高,可移植性更强,推荐使用。不等于的目的是查询出与条件不符和结果,格式如下:select cname1,cname2,... from tname where cname <> cval; 或 select cname1,cname2,... from tname where cname != cval;mysql> select * from user2; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | +----+-------+-----+----------+-----+ 3 rows in set mysql> select * from user2 where age<>20; +----+-------+-----+---------+-----+ | id | name | age | address | sex | +----+-------+-----+---------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 3 | sol | 21 | xiamen | 0 | +----+-------+-----+---------+-----+ 2 rows in set大于小于(> <)一般用于数值或者日期、时间类型的比较,格式如下:select cname1,cname2,... from tname where cname > cval; select cname1,cname2,... from tname where cname < cval; select cname1,cname2,... from tname where cname >= cval; select cname1,cname2,... from tname where cname <= cval;mysql> select * from user2 where age>20; +----+-------+-----+---------+-----+ | id | name | age | address | sex | +----+-------+-----+---------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 3 | sol | 21 | xiamen | 0 | +----+-------+-----+---------+-----+ 2 rows in set mysql> select * from user2 where age>=20; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | +----+-------+-----+----------+-----+ 3 rows in set mysql> select * from user2 where age<21; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 2 | helen | 20 | quanzhou | 0 | +----+-------+-----+----------+-----+ 1 row in set mysql> select * from user2 where age<=21; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | +----+-------+-----+----------+-----+ 3 rows in set运算符说明AND多个条件都成立OR多个条件中满足一个NOT对条件进行取非操作AND(且)当需要多个条件进行数据过滤的时候,使用这种方式,and的每个表达式都是要成立,过滤出来的数据就是用户需要的。下面过滤出年龄和性别两个条件都成立的数据,语法格式如下:select cname1,cname2,... from tname where cname1 operators cval1 and cname2 operators cval2mysql> select * from user2; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | | 4 | weng | 33 | guizhou | 1 | +----+-------+-----+----------+-----+ 4 rows in set mysql> select * from user2 where age >20 and sex=1; +----+-------+-----+---------+-----+ | id | name | age | address | sex | +----+-------+-----+---------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 4 | weng | 33 | guizhou | 1 | +----+-------+-----+---------+-----+ 2 rows in setOR(或)当多个条件中只要满足一个条件即进行数据过滤。下面条件过滤出年龄大于21岁和小于21岁的数据,语法格式如下:select cname1,cname2,... from tname where cname1 operators cval1 or cname2 operators cval2mysql> select * from user2; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | | 4 | weng | 33 | guizhou | 1 | +----+-------+-----+----------+-----+ 4 rows in set mysql> select * from user2 where age>21 or age<21; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 2 | helen | 20 | quanzhou | 0 | | 4 | weng | 33 | guizhou | 1 | +----+-------+-----+----------+-----+ 2 rows in setNOT IN(对包含查询取反)我们上面已经学习过了not得用户,对not后面执行得表达式进行取反得操作,测试下:mysql> select * from user2; +----+--------+-----+----------+-----+ | id | name | age | address | sex | +----+--------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | | 4 | weng | 33 | guizhou | 1 | | 5 | selina | 25 | taiwang | 0 | +----+--------+-----+----------+-----+ 5 rows in set mysql> select * from user2 where address not in('fuzhou','quanzhou','xiamen'); +----+--------+-----+---------+-----+ | id | name | age | address | sex | +----+--------+-----+---------+-----+ | 4 | weng | 33 | guizhou | 1 | | 5 | selina | 25 | taiwang | 0 | +----+--------+-----+---------+-----+ 2 rows in set空值检查IS NULL/IS NOT NULL判断是否为空,语法格式如下,这边注意的是,对值为null的数据,各种比较运算符、like、between and、in、not in查询都不起作用,只有is null 能够过滤出来。 select cname1,cname2,... from tname where cname is null; 或者 select cname1,cname2,... from tname where cname is not null;mysql> select * from user2 where address is null; +----+--------+-----+---------+-----+ | id | name | age | address | sex | +----+--------+-----+---------+-----+ | 5 | selina | 25 | NULL | 0 | +----+--------+-----+---------+-----+ 1 row in set mysql> select * from user2 where address is not null; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | | 4 | weng | 33 | guizhou | 1 | +----+-------+-----+----------+-----+ 4 rows in set总结1、like表达式中的%匹配一个到多个任意字符,_匹配一个任意字符2、空值查询需要使用IS NULL或者IS NOT NULL,其他查询运算符对NULL值无效。即使%通配符可以匹配任何东西,也不能匹配值NULL的数据。3、建议创建表的时候,表字段不设置空,给字段一个default 默认值。4、MySQL支持使用NOT对IN 、BETWEEN 和EXISTS子句取反 。
-
MySQL 数据库中的表结构确立后,表中的数据代表的意义就已经确定。而通过 MySQL 运算符进行运算,就可以获取到表结构以外的另一种数据。例如,学生表中存在一个 birth 字段,这个字段表示学生的出生年份。而运用 MySQL 的算术运算符用当前的年份减学生出生的年份,那么得到的就是这个学生的实际年龄数据。MySQL 支持 4 种运算符,分别是:1) 算术运算符执行算术运算,例如:加、减、乘、除等。2) 比较运算符包括大于、小于、等于或者不等于,等等。主要用于数值的比较、字符串的匹配等方面。例如:LIKE、IN、BETWEEN AND 和 IS NULL 等都是比较运算符,还包括正则表达式的 REGEXP 也是比较运算符。3) 逻辑运算符包括与、或、非和异或等逻辑运算符。其返回值为布尔型,真值(1 或 true)和假值(0 或 false)。4) 位运算符包括按位与、按位或、按位取反、按位异或、按位左移和按位右移等位运算符。位运算必须先将数据转换为二进制,然后在二进制格式下进行操作,运算完成后,将二进制的值转换为原来的类型,返回给用户。算术运算符算术运算符是 SQL 中最基本的运算符,MySQL 中的算术运算符如下表所示。算术运算符说明+加法运算-减法运算*乘法运算/除法运算,返回商%求余运算,返回余数比较运算符比较运算符的语法格式为:<表达式1> {= | < | <= | > | >= | <=> | < > | !=} <表达式2>MySQL 支持的比较运算符如下表所示。比较运算符说明=等于<小于<=小于等于>大于>=大于等于<=>安全的等于,不会返回 UNKNOWN<> 或!=不等于IS NULL 或 ISNULL判断一个值是否为 NULLIS NOT NULL判断一个值是否不为 NULLLEAST当有两个或多个参数时,返回最小值GREATEST当有两个或多个参数时,返回最大值BETWEEN AND判断一个值是否落在两个值之间IN判断一个值是IN列表中的任意一个值NOT IN判断一个值不是IN列表中的任意一个值LIKE通配符匹配REGEXP正则表达式匹配下面分别介绍不同的比较运算符的使用方法。1) 等于运算符“=”等号“=”用来判断数字、字符串和表达式是否相等。如果相等,返回值为 1,否则返回值为 0。数据进行比较时,有如下规则:若有一个或两个参数为 NULL,则比较运算的结果为 NULL。若同一个比较运算中的两个参数都是字符串,则按照字符串进行比较。若两个参数均为正数,则按照整数进行比较。若一个字符串和数字进行相等判断,则 MySQL 可以自动将字符串转换成数字。2) 安全等于运算符“<=>”用于比较两个表达式的值。当两个表达式的值中有一个为空值或者都为空值时,将返回 UNKNOWN。对于运算符“<=>”,当两个表达式彼此相等或都等于空值时,比较结果为 TRUE;若其中一个是空值或者都是非空值但不相等时,则为 FALSE,不会出现 UNKNOWN 的情况。3) 不等于运算符“<>”或者“!=”“<>”或者“!=”用于数字、字符串、表达式不相等的判断。如果不相等,返回值为 1;否则返回值为 0。这两个运算符不能用于判断空值(NULL)。4) 小于或等于运算符“<=”“<=”用来判断左边的操作数是否小于或等于右边的操作数。如果小于或等于,返回值为 1;否则返回值为 0。“<=”不能用于判断空值。5) 小于运算符“<”“<”用来判断左边的操作数是否小于右边的操作数。如果小于,返回值为 1;否则返回值为 0。“<”不能用于判断空值。6) 大于或等于运算符“>=”“>=”用来判断左边的操作数是否大于或等于右边的操作数。如果大于或等于,返回值为 1;否则返回值为 0。“>=”不能用于判断空值。7) 大于运算符“>”“>”用来判断左边的操作数是否大于右边的操作数。如果大于,返回值为 1;否则返回值为 0。“>”不能用于判断空值。8) IS NULL(或者 ISNULL)IS NULL 和 ISNULL 用于检验一个值是否为 NULL,如果为 NULL,返回值为 1;否则返回值为 0。9) IS NOT NULLIS NOT NULL 用于检验一个值是否为非 NULL,如果为非 NULL,返回值为 1;否则返回值为 0。10) BETWWEN AND语法格式为:<表达式> BETWEEN <最小值> AND <最大值>若<表达式>大于或等于<最小值>,且小于或等于<最大值>,则 BETWEEN 的返回值为 1;否则返回值为 0。11) LEAST语法格式为:LEAST(<值1>,<值2>,…,<值n>)其中,值 n 表示参数列表中有 n 个值。存在两个或多个参数的情况下,返回最小值。若任意一个自变量为 NULL,则 LEAST() 的返回值为 NULL。12) GREATEST语法格式为:GREATEST (<值1>,<值2>,…,<值n>)其中,值 n 表示参数列表中有 n 个值。存在两个或多个参数的情况下,返回最大值。若任意一个自变量为 NULL,则 GREATEST() 的返回值为 NULL。13) ININ 运算符用来判断操作数是否为 IN 列表中的一个值。如果是,返回值为 1;否则返回值为 0。14) NOT INNOT IN 运算符用来判断表达式是否为 IN 列表中的一个值。如果不是,返回值为 1;否则返回值为 0。逻辑运算符在 SQL 语言中,所有逻辑运算符求值所得的结果均为 TRUE、FALSE 或 NULL。在 MySQL 中分别体现为 1(TRUE)、0(FALSE)和 NULL。MySQL 中的逻辑运算符如下表所示。逻辑运算符说明NOT 或者 !逻辑非AND 或者 &&逻辑与OR 或者 ||逻辑或XOR逻辑异或下面分别介绍不同的逻辑运算符的使用方法。1) NOT 或者 !逻辑非运算符 NOT 或者 !,表示当操作数为 0 时,返回值为 1;当操作数为非零值时,返回值为 0;当操作数为 NULL 时,返回值为 NULL。2) AND 或者 &&逻辑与运算符 AND 或者 &&,表示当所有操作数均为非零值并且不为 NULL 时,返回值为 1;当一个或多个操作数为 0 时,返回值为 0;其余情况返回值为 NULL。3) OR 或者 ||逻辑或运算符 OR 或者 ||,表示当两个操作数均为非 NULL 值且任意一个操作数为非零值时,结果为 1,否则结果为 0;当有一个操作数为 NULL 且另一个操作数为非零值时,结果为 1,否则结果为 NULL;当两个操作数均为 NULL 时,所得结果为 NULL。4) XOR逻辑异或运算符 XOR。当任意一个操作数为 NULL 时,返回值为 NULL;对于非 NULL 的操作数,若两个操作数都不是 0 或者都是 0 值,则返回结果为 0;若一个为 0,另一个不为非 0,则返回结果为 1。位运算符位运算符是用来对二进制字节中的位进行移位或者测试处理的。MySQL 中提供的位运算符如下表所示。位运算符说明|按位或&按位与^按位异或<<按位左移>>按位右移~按位取反,反转所有比特下面分别介绍不同的位运算符的使用方法。1) 位或运算符“|”位或运算的实质是将参与运算的两个数据按对应的二进制数逐位进行逻辑或运算。若对应的二进制位有一个或两个为 1,则该位的运算结果为 1,否则为 0。2) 位与运算符“&”位与运算的实质是将参与运算的两个数据按对应的二进制数逐位进行逻辑与运算。若对应的二进制位都为 1,则该位的运算结果为 1,否则为 0。3) 位异或运算符“^”位异或运算的实质是将参与运算的两个数据按对应的二进制数逐位进行逻辑异或运算。对应的二进制位不同时,对应位的结果才为 1。如果两个对应位都为 0 或者都为 1,则对应位的结果为 0。4) 位左移运算符“<<”位左移运算符“<<”使指定的二进制值的所有位都左移指定的位数。左移指定位数之后,左边高位的数值将被移出并丢弃,右边低位空出的位置用 0 补齐。语法格式为表达式<<n,这里 n 指定值要移位的位数。5) 位右移运算符“>>”位右移运算符“>>”使指定的二进制值的所有位都右移指定的位数。右移指定位数之后,右边高位的数值将被移出并丢弃,左边低位空出的位置用 0 补齐。语法格式为表达式>>n,这里 n 指定值要移位的位数。6) 位取反运算符“~”位取反运算符的实质是将参与运算的数据按对应的二进制数逐位反转,即 1 取反后变 0,0 取反后变为 1。运算符的优先级决定了不同的运算符在表达式中计算的先后顺序,下表列出了 MySQL 中的各类运算符及其优先级。优先级由低到高排列运算符1=(赋值运算)、:=2II、OR3XOR4&&、AND5NOT6BETWEEN、CASE、WHEN、THEN、ELSE7=(比较运算)、<=>、>=、>、<=、<、<>、!=、 IS、LIKE、REGEXP、IN8|9&10<<、>>11-(减号)、+12*、/、%13^14-(负号)、〜(位反转)15!可以看出,不同运算符的优先级是不同的。一般情况下,级别高的运算符优先进行计算,如果级别相同,MySQL 按表达式的顺序从左到右依次计算。另外,在无法确定优先级的情况下,可以使用圆括号“()”来改变优先级,并且这样会使计算过程更加清晰。
-
1、首先。临时表是session级别的,当前session创建的表,在其他session中看不到。session 1:mysql> create temporary table test3 (id_tmp int)engine=innodb; Query OK, 0 rows affected (0.00 sec)session 2:mysql> show create table test3\G ERROR 1146 (42S02): Table 'test.test3' doesn't exist2、临时表在session中,可以和正式的表重名。mysql> create table test2 (id int)engine=innodb; Query OK, 0 rows affected (0.01 sec) mysql> create temporary table test2 (id_tmp int)engine=innodb; Query OK, 0 rows affected (0.00 sec)3、当数据库中物理表和临时表的时候,使用show create table查看的是临时表的内容:mysql> show create table test2\G *************************** 1. row *************************** Table: test2 Create Table: CREATE TEMPORARY TABLE `test2` ( `id_tmp` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)4、临时表drop掉之后,show create table查看的是物理表的内容。mysql> show tables like "test2"; +------------------------+ | Tables_in_test (test2) | +------------------------+ | test2 | +------------------------+ 1 row in set (0.00 sec) mysql> drop table test2; Query OK, 0 rows affected (0.00 sec) mysql> show tables like "test2"; +------------------------+ | Tables_in_test (test2) | +------------------------+ | test2 | +------------------------+ 1 row in set (0.00 sec)5、show tables命令,不能看到临时表。6、不同的session中可以创建同名的临时表。7、临时表保存方法 在MySQL中,使用.frm来保存表结构,而使用.ibd来保存表数据,.frm文件一般是放在tmpdir这个参数指定的目录下面的。台式机windows平台下MySQL的如下:mysql> show variables like "%tmpdir%"; +-------------------+-------------------------------------------------+ | Variable_name | Value | +-------------------+-------------------------------------------------+ | innodb_tmpdir | | | slave_load_tmpdir | C:\WINDOWS\SERVIC~1\NETWOR~1\AppData\Local\Temp | | tmpdir | C:\WINDOWS\SERVIC~1\NETWOR~1\AppData\Local\Temp | +-------------------+-------------------------------------------------+ 3 rows in set, 1 warning (0.01 sec) MySQL5.6版本下,会生成一个.ibd的文件来保存临时表。MySQL5.7版本下,引入了临时文件表空间,专门用来存放临时文件的数据。当我们使用不同的session来创建相同名称的临时表的时候,会发现临时表的目录下面存在不同名称的临时表文件:这些临时表在内存中是通过链表的方式来表示的,如果一个session中包含两个临时表,MySQL会创建一个临时表的链表,将这两个临时表连接起来,实际的操作逻辑中,如果我们执行了一条SQL,MySQL会遍历这个临时表的链表,检查是否有这个SQL中指定表名字的临时表,如果有临时表,优先操作临时表,如果没有临时表,则操作普通的物理表。8、临时表在主从复制中的注意点临时表由于是session级别的,那么在session退出的时候,是会删除临时表的。但是主节点中并没有对临时表进行显示的操作,而是关闭session即可删除,那么从节点如何知道什么时候才能删除临时表呢?假设主节点进行如下SQL:crete table tbl; create temporary table tmp like tbl; insert into tmp values (0,0); insert into tbl select * from tmp;9、不同线程的同名临时表在从库上如何同时存在? 我们知道临时表是session级别的,而且不同session之间的临时表可以重名,在从库进行binlog回放的时候,从库是如何知道这些重名的临时表分别属于哪个事务的呢? 这个概念的理解可以参考函数中的形参和实参的概念,形参和实参可能有同样的名字,进行赋值的时候,二者的指针值是不一样的,所以同名的参数,对编译器来讲,由于指针值不一样,所以不会出现错误。 MySQL维护数据表,除了物理上要有文件外,内存里面也有一套机制区别不同的表,每个表都对应一个table_def_key。而这个table_def_key的值是由"库名字+表名字+server_id+thread_id"组成的,因为thread_id不同,所以在从库中进行操作的时候,是不会冲突的。
-
案例1案例一,代码摘抄来自一企业培训材料,主要代码逻辑是打印每课成绩,并找出学生非F级别课程统计平均分数:class CourseGrade { public String title; public char grade; } public class ReportCard { public String studentName; public ArrayList<CourseGrade> cliens; public void printReport() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); System.out.println("Course Title Grade"); Iterator<CourseGrade> grades = cliens.iterator(); CourseGrade grade; double avg = 0.0d; while (grades.hasNext()) { grade = grades.next(); System.out.println(grade.title + " " + grade.grade); if (!(grade.grade == 'F')) { avg = avg + grade.grade - 64; } } avg = avg / cliens.size(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + avg); } }成员变量采用public,缺少数据封装性没有判断cliens是否为空,可能除以0值。注:假定它不会为空,另外逻辑可能有问题,为什么统计总分是非F课程,除数却是所有课程Size,先忽略这个问题avg这个变量多个用途,即是总分,又是平均分cliens变量名难以理解!(grade.grade == 'F') 有点反直觉while循环干了两件事,打印每课的成绩,也统计了分数培训材料并未给标准解题,尝试优化一下代码,采用Java8的Stream来简化计算过程,并对代码进行了分段:public void printReport2() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); System.out.println("Course Title Grade"); cliens.forEach(it -> System.out.println(it.title + " " + it.grade)); double total = cliens.stream().filter(it -> it.grade != 'F') .mapToDouble(it -> it.grade - 64).sum(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + total / cliens.size()); }进一步优化,把各类打印抽取各自函数: private void printHeader() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); } private void printGrade() { System.out.println("Course Title Grade"); cliens.forEach(it -> System.out.println(it.title + " " + it.grade)); } private void printAverage() { double total = cliens.stream().filter(it -> it.grade != 'F') .mapToDouble(it -> it.grade - 64).sum(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + total / cliens.size()); } public void printReport3() { printHeader(); printGrade(); printAverage(); }注:如果只算非F的平均分,可以一行搞定:double avg = cliens.stream().filter(it -> it.grade != 'F').mapToDouble(it -> it.grade - 64).average().orElse(0.0d);案例二:再看一段代码:List<Integer> tanscationsIds = transcations.parallelStream() .filter(it -> it.getType() == Transcation.GROCERY) .sorted(comparing(Transcation::getValue).resersed()) .map(Transcation::getId) .collect(Collectors::toList());代码非常清晰:过滤出类型为GROCERY的交易记录按其value值进行倒排序各自取其Id字段输出Id列表这看起来是不是像这样一条SQL语句:select t.id from tanscations t where t.type == 'GROCERY' order by t.value desc1.1 背后的知识目前Java8已广泛使用,对于Stream与Lambda应习以为常了,而不再是一种炫技。网上也有非常多的教程,若有同学还不熟悉他们的用法,可以多找找材料熟悉一下。Stream正如其名,像一条数据生产流水线,逐步叠加中间操作(算法和计算),把数据源转换为另一个数据集。笔者很早以前学过C#,接触过LINQ(Language Integrated Query),它比Java的Stream和Lambda用法更为清晰简洁,先给个简单示例:var result = db.ProScheme.OrderByDescending(p => p.rpId).Where(p => p.rpId > 10).ToList();LINQ为数据查询而生,可以算是DSL(Domain Specific Language)了,背后也是函数式编程(FP)一套理念,先记住其中两点:Monad 是一种设计模式,表示将一个运算过程,通过函数拆解成互相连接的多个步骤Lambda表达式 是一个匿名函数,Lambda表达式基于数学中的λ演算得名FP还有其它的特性:模式匹配,柯里化,偏函数,闭包,尾递归等。对FP感觉兴趣的同学不妨找找材料学习一下。现在的主流语言,都引入一些FP特性来提升语言在数据上的表达能力。C++11引入Lambda表达式,并提供<algorithm>,<functional>两个基础库,一个简单示例:int foo[] = { 10, 20, 5, 15, 25 };std::sort(foo, foo+5, [](int a,int b){return a > b;});Python提供functools库来简化一些函数式编程(还是相当的弱),一个简单示例:foo = ["A", "a", "b", "B"]sorted(foo, key=functools.cmp_to_key(locale.strcoll))2 函数式编程当然,面向对象语言中增加lambda这类特征不能就称为函数式编程了,大部分只不过是语法糖。是采用什么编程范式不在于语言的语法,而是在于思维方式。面向对象编程(OOP)在过去20多年非常成功,而函数式编程(FP)也不断地发展,他们相生相息,各自解决不同的场景问题:面向对象可以理解为是对数据的抽象,比如把一个事物抽象成一个对象,关注的是数据。函数式编程是一种过程抽象的思维,就是对当前的动作去进行抽象,关注的是动作。现实业务需求往往体现为业务活动,它是面向过程的,即先输入数据源,在一定条件下,进行一系列的交互,再输出结果。那面向过程与函数式的的区别是什么:面向过程可以理解是把做事情的动作进行分解多个步骤,所以有if/while这类语法支撑,走不同的分支步骤。函数式相比面向过程式,它更加地强调执行结果而非执行过程,利用若干个简单的执行单元让计算结果不断渐近,逐层推导复杂的运算,而不是像面向过程设计出复杂的执行过程,所以纯函数式编程语言中不需要if/while这类语法,而是模式匹配,递归调用等。面向对象的编程通过封装可变的部分来构造能够让人读懂的代码,函数式编程则是通过最大程度地减少可变的部分来构造出可让人读懂的代码。我们从Java的Stream实现也看到函数式的另一个特点:函数不维护任何状态,上下文的数据是不变的,传入的参数据处理完成之后再扔出来。结合上面的理解,我们可以先把世界事物通过OOP抽象为对象,再把事物间的联系与交互通过FP抽象为执行单元,这种结合或许是对业务活动的实现一种较好的解决方式。3 避免单一范式一提到编程范式,很容易联想到宗教的虔诚,每种宗教所表达信条都有一定合理性,但如果一直只遵循一种教条,可能也被让自己痛苦不堪。编程范式也是如此,正如Java在1.8之前是纯面向对象式,你就会觉得它非常繁琐。也如Erlang是纯函数式,你就会发现有时简单的逻辑处理会非常复杂。近些年来,由于数据分析、科学计算和并行计算的兴起,让人认识到函数式编程解决数据领域的魅力,它也越来越受欢迎。在这些领域,程序往往比较容易用数据表达式来表达,采用函数式可以用很少代码来实现。现实的业务软件,很多的逻辑其实也是对数据的处理,最简单是对数据的CURD,以及数据的组合、过滤与查询。所以函数式编程在许多语言中都得到支持,提升了对数据处理的表达能力。了解新的编程范式在适当的时候使用它们,这会使你事半功倍。无论什么编程范式,他们都是工具,在你的工具箱中,可能有锤子,螺丝刀…,这个工具在什么时候使用,取决待解决的问题。4 结语本文的案例只是一个引子,主要是想给你带来函数式编程的一些理念,函数式给我们解决业务问题提供了另一种思维方式:如何高效简洁地对数据查询与变换。许多语言都支持函数式一些能力,需要我们不断地学习,在合理的场景下使用他们。转自 csdn华为云
-
本节收录了稍作剪辑的PEP 8摘要(Python Enhancement Proposal,Python增强提案)。PEP 8由Guido van Rossum和Barry Warsaw撰写,是Python的最接近编程风格手册的东西。这里省略了一些比较具体的部分,但主要内容都已包括。应该尽可能让代码遵守PEP 8规范,代码会由此更具Python风格。访问Python官方网站的文档部分并搜索PEP,就可以获得PEP 8全文及Python历史上发布的所有其他PEP。PEP既是Python历史和经验的绝佳来源,也是当前议题和将来计划的解释。A.3.1 简介本文档给出的Python编码约定,适用于由Python主发行版本中的标准库构成的代码。有关Python的C实现中的C代码风格指南,参见相应的PEP[1]。本文档改编自Guido最初的Python风格指南文章,并加入了Barry风格指南的一些内容。如果与Guido的风格规则存在冲突,应该遵从本PEP。本PEP可能尚未完结(其实可能永远不会完结)。盲目的一致性是头脑简单的表现Guido的一个重要观点是,代码被阅读的次数远多于被编写的次数。本指南旨在提高代码的可读性,使各种各样的Python代码能保持风格一致。正如PEP 20[2]所述,“Readability counts”(注重可读性)。风格指南是讨论一致性的。与风格指南保持一致很重要。维持同一个项目内部的一致性更加重要。而保证同一个模块和函数内部的一致性则最重要。然而最最重要的是,知道何时应打破一致性,有时风格指南并不适用。如果心存疑虑,请采用自己的最佳判断。请看看别人的例子并做出最佳决定。不要犹豫,尽管发出疑问。以下是两个打破规范的好理由。如果应用风格指南会让代码的可读性变差,甚至对于习惯阅读遵守本规范代码的人来说也是如此。需要与周边的代码保持一致,而这些代码并未遵守规范(可能是历史原因造成的),尽管这也可能是个收拾别人烂摊子的机会(真正的极限编程风格)。A.3.2 代码布局1.缩进每级缩进采用4个空格。为了对付那些确实陈旧的代码,又不愿做出清理,那么可以继续沿用8个空格长度的制表符。2.制表符还是空格绝对禁止制表符和空格的混用。最流行的Python缩进方式是只使用空格。第二流行的方式是只使用制表符。混合使用制表符和空格进行缩进的代码,应该转换为只使用空格的方式。如果调用Python命令行解释器时带上-t参数,它就会对非法混用制表符和空格的代码发出警告。如果用了-tt参数,这些警告就会上升为错误。强烈推荐使用这些参数!对全新的项目而言,强烈建议只用空格缩进,换掉所有的制表符。大部分编辑器都具备将制表符替换为空格的便捷功能。3.最大行长所有行都应限制在79个字符以内。将行长限制在80个字符的设备还有很多,而且将窗口限制为80个字符宽就可以并排放置多个窗口。这些设备上的默认换行会破坏代码的外观,增加理解的难度。因此,请将所有行都限制在79个字符以内。对于连续的大段文字(文档字符串或注释),建议将行长限制在72个字符以内。对长行进行换行的首选方案,是利用Python隐含的行连接特性,在圆括号、方括号和大括号内部进行断行。必要时可以在表达式外面多加一对圆括号,不过有时候用反斜杠会更好看些。请确保对后续行进行适当的缩进。打断二元运算符的首选位置是在运算符之后,而不是运算符之前。下面给出一些例子:4.空行顶级函数和类定义之间,请用两个空行分隔。类内部的各个方法定义之间,请用1个空行分隔。为了让有关联的函数成组,可以在各函数组之间有节制地添加空行。相互关联的一组单行函数之间,可以省略空行,如一组函数的伪实现(dummy implementation)。函数内部可以有节制地用空行来区分出各个逻辑部分。Python可将Ctrl+L(^L)换页符接受为空白符。很多工具都将其视为分页符,所以可以利用其进行分页,使得文件中的关联部分单独成页。5.导入导入语句通常应单独成行,例如:import osimport sys不要像下面这样写在一起:import sys, os不过下面的写法没有问题:from subprocess import Popen, PIPE导入语句通常位于文件的顶部,紧挨着模块注释和文档字符串后面,在模块全局变量和常量定义之前。导入语句应按照以下顺序进行分组。(1)标准库的导入。(2)相关第三方库的导入。(3)本地应用程序/库——特定库的导入。每组导入语句之间请加入1个空行。任何对应的__all__声明都应位于导入语句之后。非常不推荐对内部包的导入使用相对导入语法。请始终对所有导入都使用绝对包路径。即便Python 2.5现在已完全实现了PEP 328[3],它的显式相对导入语法也是强烈不推荐的。绝对导入的可移植性更好,通常可读性也会更好。{:—}如果是从包含类的模块中导入类,通常可以采用如下写法:from myclass import MyClassfrom foo.bar.yourclass import YourClass如果上述写法会导致本地命名冲突,就采用如下写法:import myclassimport foo.bar.yourclass然后用myclass.MyClass和foo.bar.yourclass.YourClass表示类。6.表达式和语句内的空白符讨厌之事——以下场合应避免使用多余的空白符。紧靠小括号、中括号或大括号内部。 正确:错误:紧挨着逗号、分号或冒号之前。 正确:错误:紧挨着函数参数列表的左括号之前。正确:错误:紧挨着索引或切片操作的左括号之前。正确:错误:为了与另一条赋值或其他语句对齐,在运算符两边使用多个空格。正确:错误:7.其他建议始终在以下二元操作符两侧各放1个空格:赋值(=)、增量赋值(+=,-=等)、比较(==、<、>、!=、<>、<=、>=、in、not、in、is、is not)、布尔(and、or、not)。在数学运算符两侧放置空格。 正确:错误:在用于指定关键字参数或默认参数值时,请勿在=两边使用空格。正确:错误:通常不鼓励使用复合语句,也就是在同一行放置多条语句。正确:最好不要:虽然有时候将小块代码和if/for/while放在同一行没什么问题,但多行语句绝对不能如此。同时还要避免过长代码行的折叠!最好不要:绝对不要:本文截选自最新上架的《Python 快速入门》第3版《Python 快速入门》第3版本书是Python专业人士Naomi Ceder编写的Python语言的综合指南。她是一位经验丰富的教学者,她既能让读者关注语言的细节,又能使其具备解决实际问题的能力。本书中配有大量贴切的示例和边做边学的习题,有助于读者掌握每一个重要概念。无论读者是要抓取网站内容还是想玩转嵌套元组,都会赞叹本书的清晰、专注和对细节的重视。本书主要内容● 明确涵盖Python 3。● 全面介绍核心库、包和工具。● 配备精深的习题。● 新增5章与数据科学相关的内容。本书专为熟悉编程概念的读者编写,但不要求读者具备Python的使用经验。本文转载自异步社区。原文链接:https://www.epubit.com/articleDetails?id=44deb149f0f94700b1b6ae4766e162d4
-
python基础语法难点突破1.面向对象类的基本使用知识点:属性:类属性、实例对象属性方法:实例方法、类方法、静态方法类可以调用哪些内容:类属性、类方法、静态方法代码示例:class A(object): # 类属性 class_a = 20 def __init__(self): # 实例对象属性 self.a = 10 # 实例方法 def a_print(self): print("a_print") # 类方法 @classmethod def class_print(cls): print('class_print') # 静态方法 @staticmethod def static_print(): print("static_print")# 类调用类属性,不能调用实例对象属性print(A.class_a)# 使用实例化对象调用实例对象属性print(A().a)# 使用类调用类方法A.class_print()# 使用类调用静态方法A.static_print()# 调用实例方法的两种方式A.a_print(A())A().a_print()12345678910111213141516171819202122232425262728293031323334352.面向对象类的调用和属性知识点:在一个类中想要调用另一个类的方法和属性的方法:继承、属性赋值的形式代码示例:class A(object): class_a = 20 def __init__(self): self.a = 10 def a_print(self): print("a_print") @classmethod def class_print(cls): print('class_print') @staticmethod def static_print(): print("static_print")# 继承class B(A): def b_print(self): print("b_print")B().b_print()B().a_print()# 属性赋值的形式class C(object): obj_a = A() def c_print(self): print('c_print')# 调用A中的方法C.obj_a.a_print()12345678910111213141516171819202122232425262728293031323334353637383.面向对象super和@property的使用知识点:super作用:super() 函数是用于调用父类(超类)的一个方法。super使用场景:重写父类方法,在父类方法的基础上,新增一些业务逻辑使用@property装饰器可以直接通过方法名来访问方法,不需要再在后面使用"()"代码示例:class A(object): def a_print(self): print("a_print")class B(A): def a_print(self): # 调用父类方法 super().a_print() print("add_data") @property def data(self): print("data")B().a_print()# 直接以调用属性的形式调用方法B().data
-
摘要:如何才能学好JS?在这里给大家总结一些学习Js的经验,希望能对你们有所帮助。在我们第一阶段完成HTML+CSS的学习之后,很多同学都会被第二阶段JS难倒——JS语法、JS数据类型、JS对象,Js给我们的印象总是那么的“复杂”,因为它相比html来说是动态的,是编程语言,更深奥一些。想要熟练掌握js难度很大,不过如果你把知识点梳理清楚,真正的理解并加以运用,你就可以掌握它。那么该如何才能学好JS?在这里给大家总结一些学习Js的经验,希望能对你们有所帮助。Js给人那种感觉的原因多半是因为它如下的特点:第一:本身知识很抽象、晦涩难懂,如:闭包、内置对象、DOM。第二:本身内容很多,如函数库、对象库就一大堆。第三:混合多种编程思想。它里面不但牵涉面向过程编程思想,又有面向对象编程思想,同时,它的面向对象还和别的编程语言(如:C++,JAVA,PHP)不大一样。就好像又是新的一样,让你对曾经学的面向对象产生了怀疑…那么,怎么才能在js领域内学的轻松一些呢?以我亲身经历和老师的言传身教总结了一些js学习经验:1.清楚js的定位时刻都不能忘记,否则很容易犯不清楚js是什么的错误。不要学了很久就知道js是编程语言,就是写代码,而且特点就是乱七八糟就完了,那样是学不好js的。要时时抓住它的地位,确切的说是它在整个Web中的地位:它属于前端的核心,主要用来操控和重新调整DOM,通过修改DOM结构,从而来达到修改页面效果的目的。要用这个中心思想去指导后续的一切js的学习,并且形成条件反射。2.清晰的学习路线这个只能是自己慢慢摸索或过来人点拨。我的学习路线如下:A:js基础部分,如:定义变量、函数、数组、字符串等的处理,内置函数、内置对象等;B:js面向过程编程思想,封装出各个函数,试着用这些去做一些常见的小功能,如:99乘法表、选项卡、自定义多选按钮、自定义播放器、3D相册,省市区三级联动,鼠标的动效;C:js面向对象编程思想,所谓万物皆对象,试着去封装一些你自己的对象,提供出有意义的接口出来;D:学了上述的内容,之后学常用的库,这里必须学jquery;//以后我们会了解到3.自律坚持写代码不要一时兴起,三分钟热度,看到别人用js做了一个炫酷的**页,你就大喊大叫的我也来我也来,殊不知别人背地里把基础打扎实了,才有这个成果,而你在三天打鱼两天晒网,写一个小项目就会发现自己忘记很多知识点,而垂头丧气。编程语言从来不是一下子就能学好的,都是时间的积累,坚持练习,不断的完善自己的短处,所以说,自律坚持非常重要!!!4.多练多写学习js并不是跟着张宇老师,看着他敲代码,看着他说一些代码知识,说了很多注意事项,你当时可能听懂了,过了一段时间,当你写这个代码时,脑子:我会写! 手:??????就会十分尴尬,明明当时听懂了呀,可为什么........因为你没有形成深刻的记忆,学习js最好是多练习多写代码,做一些你感兴趣的小项目,实现你想要的功能,不会的去查资料,然后多练多写的同时,也要看看老师是怎么写代码的,思维也很重要。5.从多角度去学习和领悟充分调动你所学的东西,从多角度去做某一功能,锻炼自己的思维,能优化代码就尽量优化,避免冗杂,比如说:以前你是从面向过程角度做的,现在改为从面向对象的角度再来做,或者继续做成可以直接使用的插件,提供属性、方法等出来。争取让你做的这个功能逐渐能使用到实际项目中来。这样的好处:既综合应用了你的所学,又能有实际意义,两全其美。6.注意培养自信心此时的你,不适合一来就看很复杂很炫的网页效果的源代码,在没有任何基础的情况下直接学这些,会严重打击你的自信心,因此切记因小失大,注意写代码是循序渐进的,而不是一飞冲天。记住此时你是弱小的,你需要的是培养信心,而不是反过来,否则结局很可能是“三天打鱼两天晒网”,离学有所成也就遥遥无期了。7.多写学**结这种总结不但包括源代码、显示效果截图,还应该很容易犯的错误和对应的解决方法以及最后一两句精简的结论性语句。对自己写的总结不是写完了就了事了,要多回顾、多改进、多精简。到做项目的时候,应该是看里面的一两句话就知道是讲什么了,而不要再去看长篇大论了。8.构建专属知识导图这个可以让你越学越清晰,你可以按你喜欢的任何形式去做,只要自己印象深刻就行。注意:知识导图也应该是经常修改、修正,让它更合理、更清晰。总结的js的知识导图,能够认真看完就是一次对 JavaScript 的回顾与提升,可以很好的检验基础。俗话说,三分天注定,七分靠打拼,爱拼才会赢,那么加油吧!
-
1.结合方向只有三个是从右往左,其余都是从左往右。2.所有双目运算符中只有赋值运算符的结合方向是从右往左。3.另外两个从右往左结合的运算符也很好记,因为它们很特殊:一个是单目运算符,一个是三目运算符。4.C语言中有且只有一个三目运算符。5.逗号运算符的优先级最低,要记住。6.此外要记住,对于优先级:算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符。逻辑运算符中“逻辑非 !”除外。
-
#0. 前言背景本文主要讨论了数据库中的一个重要问题,执行效率的问题:如何有效的提高系统的效率,尤其是执行效率。随着现代CPU架构中所提供的指令越来越丰富,使得我们可以利用这些指令所带来技术优势。例如:SIMD,单指令多数据。SIMD多在处理多媒体技术方面使用,SIMD充分的利用并行方式来提升我们处理数据的能力。在一条指令中可以同时处理对个数据。因此,我们可以利用该指令集来提升数据库中的执行效率。 #1. 综述通常情况下,SIMD指令用来提升内循环的效率。使用SIMD带来两个好处:(1)一定程度上的并行化,因此某些操作可以在一定程度上进行同时处理;(2)其会减少分支条件指令,从而可以减少由于条件分支指令错误预测所带来的损害。其中:关于条件分支指令的优化。key words: elimination of conditional branch instructions.考察了数据库中重要的操作:顺序扫描;聚集操作;索引操作;join操作;以观察使用simd指令是否能够对于这些操作带来相应的性能提升。对于消除了条件分支的错误预测所带了性能呈现出线性加速的趋势。现在cpu和内存的访问速度已经成为数据库的瓶颈。 例如许多关于cpucache的工作已被广泛的讨论。如下相关论文讨论cache在数据库中的应用情况。其对于B-tree索引的影响以及其对于join操作的影响。1) Weaving relations for cache performance。2)Improving index performance through prefetching3)B-tree indexes and CPU caches4)What happens during a join? Dissecting CPU and memory optimization effects5)Making B+ trees cache conscious in main memory通过使用simd算术操作符来减少或者避免使用分支预测指令,从而能够大幅度的提升系统的性能。 #2. SIMD技术概述.SIMD技术运行一条指令在执行时候操作多个数据项。single instruction multi-data. 具有SIMD指令的包括:MMX, SSE,SSE2 (intel);VIS(Sun ultra-sparc); 3D now系列(AMD),还有MIPS,HP,Cyrix等等CPU提供商,详细信息见:技术报告:Multimedia extensions for general purpose microprocessors: A survey.紧缩型单精度浮点数的操作。源操作数为:四个32bit的浮点数,目标操作数为包含操作结果的四个32bit的浮点数。如上图所示。SIMD操作包括:比较操作,算术操作,移位操作,转换操作以及逻辑操作等等。对于是使用SIMD亦或是vector process(向量处理器)?向量处理器提供里在向量上进行高层(相对应SIMD的指令系统层级而言)的并行操作,例如:线性数组的处理。一个典型的向量可以包括:64位-51264位的元素。在这些元素上,我们可以使用单独的一条指令即可对这些元素执行并行操作。相比起向量寄存器,SIMD寄存器可以保存小数据量的元素,而向量寄存器则有一个最小数据量的限制(64 bits)。例如:在pentium 4上最多可以出来4个32bits的数据。因此,相比向量处理其而言其并行度将会变得小。但是,另一方面,由于我们所处理的数据量较小,是的在执行load指令的时候,其导致的延时将会变得小。具有较小的SIMD指令大小,使得其能够在超标量处理器中进行流水线方式执行。向量化编译器的限制向量化编译器的作用就是自动检查出将普通的代码可以将其转为可以利用SIMD技术的指令的可能并其进行相应的转换。例如:icc。 但icc存在着:风格问题(stylistic issue),硬件问题(hardware issue), 以及复杂度问题(complexity issue)。当我们代码中进程会出现:在内循环中进程伴有条件分支语句,而这些icc等编译器则无法正确将这些代码转换。因此,我们会尝试使用手工处理的方式,来处理类似的代码。 为了能够利用simd指令所带来的收益,那么需要我们数据库开发人员明确且正确的使用simd指令来提升相关数据库操作的性能。比较结果的格式在intel和amd架构中,比较的结果是以元素掩码(element mask,em) 的形式表现出来。em是一个向量,每个packed element要么全是1,要么全是0. 例如在上图中如果该操作符是属于比较操作,则上述操作结果是在一个长度为128bit的4个32bit长度的 elmenet mask中,而每个em的值,要么是1,当相等时候;要么是0, 两个操作数不相等。但是在像sun, mips等的架构中,其结果的形式是以bit vector的形式展现。由其中的每个bit来的值来代标识两个数之间的比较结果。 虽然上述说,intel和amd架构下采用的是element mask来表,但它们同样提供了bit vector模式,通过额外的指令来将element mask转换为bit vector模式。(例如:形如SIMD_bit_vector形式)。数据组织在SIMD指令中的另外一个需要我们认真考虑的问题是:数据的对齐问题(Data alignment)。例如:VIS指令需要是8-byte的对齐数据。而SSE和SSE2指令操作的是128bits的集群器,因此,数据必须是16-bytes的对齐方式,只有这样方可最大化的利用SIMD指令的性能。虽然,我们可以利用mov指令将未对齐的数据拷贝进/出SIMD寄存器中。但是,由于未对齐数据所带来的性能上的下降是也值得引起我们的注意的。 为了能够最大化的利用SIMD所带来的性能提升,我们需要保证需要操作的源数据的连续性。条件分支误测在现代的流水线化的cpu架构中,条件分支指令是一个非常令人头痛的问题,因为在流水线上的指令,是无法提取获取该条件分支指令的确切执行结果。因此,cpu一般采取预测的方式来,提取预测该分支指令的执行结果,如果该预测值与最后的实际结果相一致,则可以极大的提高指令的执行效率;但当该预测的值与实际值相反的时候,其所带来的性能损害也是巨大的。因为,此时条件语句之后的这些指令的执行结果将会被清空,并选择另外一条正确的指令执行线路执行。有测试表明,在pentium ii中一条错误的条件分支指令所带来大约17时钟周期的延时。 对于流水线指令系统,例如:pentium 4会带来大约20步的延时。当当前的处理器架构下,对于条件分支指令的5%错误预测将会导致20-30%的性能下降。#3. SIMD实现.假如我们想尝试使用simd指令,那么一种传统的方式是在我们的代价中直接使用simd指令来完成某些操作,但是直接使用simd指令进行编程不是一件容易的事情,且容易出现许多错误。为了解决这个现象,intel 编译提供了一种类似汇编功能的 c函数调用指令,instrinsics。至于gnu的g++等编译我们可以使用相关参数来来开启使用simd指令优化。 具体的使用如下链接所示。http://stackoverflow.com/questions/661338/sse-sse2-and-sse3-for-gnu-cscan-like运算符在介绍完simd的基表情况后,下面我们就看看数据库中的那些常用的运算符是如何利用simd指令来加速系统性能。在实际的使用过程中需要我们注意一点:数据的对齐问题。我们需要对于输入数据的对齐问题引起注意。术语:1)其中S表示为加速比,2)在本文中,一个基本的数值元素(整数或者浮点数)被称作是一个字(word)。3)S通常是,一个simd寄存器所能装下的字的个数,例如:128bits的simd寄存器,其S=4;例如对于如下的代码:其相应的使用SIMD指令的时候,形如下所示:典型地,simd指令有着丰富的功能,例如:比较操作,逻辑操作,算术操作等等。例如:对于上述第一段代码中的运算操作等,均有相应的simd指令与之相对应。 但是对于上述代码中存在着条件语句,因而对其并行化处理并非一件容易的事情。 同样对于可变长度的数据类型,如:字符串等,我们也不能对其进行很好的并行化处理。例如:对于 LIKE 语句。需要注意的是,在SIMD算法中不能够含有if语句。如果我们能够在SIMD_Process中避免使用if语句的话,我们就可以避免条件分支语句以及由分支判定条件错误所带来的性能损害。下面我们就来讨论一下上述代码片段中的process1以及process2函数。返回第一个匹配元素如上述的代码片段所示,当我们的x[i]满足某个条件后返回y的第一个元素y[i]。即:process1(y) 所完成的功能。此时process2将不会被执行。 因此可以给出相应的simd版本 SIMD_Process:当我们的条件 condition 的选择较低时候,则意味着我们的mask中大部分值为0,那么(V != 0) 将可以节约大部分的工作。存在着另外一种情况,即所谓的唯一匹配。当我们的匹配结果最多只要一个与搜索的关键字想匹配时候,我们就可以使用唯一匹配方式来进行处理。 例如,在实际的应用中的b+树。通常在其叶子节点中的数据是具有唯一性的。例如:当 v!=0条件满足时候,在y中的S个字中只有一个是满足条件的。因此,通过上述的约束条件,我们知道有且只有一个满足条件的元组。故而,SIMD_Process的方法如下:返回索引匹配元素有指定的pos位置开始,将以pos为起点,返回所有的元素。 如下所示:其相应的SIMD版本所对应的代码如下:此外,当我们考虑到分支条件语句的时候,以及由于其内循环中的条件语句所带来的系统性能的损害。则可以SIMD_Process函数以如下方式实现:#4. SIMD版的标量聚集函数.求和以及计数对于聚集函数来说,其对应的聚集函数都可以给出相应的SIMD版本。 例如:我们对于sum函而言,传统的求值方式如下:那么对于SIMD形式的代码如下:计数功能完全可以有上述的代码来完成,我们只要把SIMD_AND的第二参数设置为1,即可为完成计数功能。最大值和最小值intel的simd指令集中,提供了相应的simd操作用来并行的方式计算两个simd单元对的最小值,同样也存在着最大值计算。我们初始化一个simd单元 ,inf用来表示最大值。同样我们也可以使用Inf来初始标识最小值的单元min。因此,求解最小值的simd版本的代码如下:上述代码的基表做法是:将非匹配的元素转换为inf,因此其将不会影响到最小值的结果。 最后,在min[1…S]中包含了最小值。 同样,求解最大值的方法同求解最小值时候相类似。唯一不同的是我们使用-inf,而不是inf。同样,我们使用SIMD_MAX指令而非SIMD_MIN指令。#5. 索引及连接处理.索引结构现代系统架构对于的索引结构有着非常大的影响,尤其是cache的性能。现有大量的文献均讨论了不同的索引组织形式与cpu cache性能之间的关系。使用simd指令可以提升索引遍历时候的速度。 将simd指令可以与cache-感知的索引结构结合起来,在现代大多数cpu架构上来获得提升索引操作的性能。 例如:我们可以使用并行方式计算hash值来提高创建hash索引的速度。 树型索引:ISAM, B+. 其中,的多维索引类型:Quad树,K-D-B 树, R树等。我们在索引的变量及计算过程中经历需要避免使用if指令,因为错误的if指令会导致系统性能的极速下降。因为在现代流行线的指令系统下,错误的预测将会导致后续已执行的错误分支上的指令被废弃。索引的内部(中间)节点操作使用simd指令来优化索引树中的查找算法。我们常用的是所谓的二分查找。与传统的每次比较一个元素而言,我们使用simd指令一次可以比较多个连续的值。 请相应的基表思想如下:我们从数组的中间部分开始进行搜索,如果我们的SIMD比较指令的比较结果全部为0,则我们在左部分进行继续搜索;当我们的比较结果全部位1的时候,我们在右部进搜索。当产生的结果为中间形式时候,则标识我们所要搜索的关键字在该simd单元中。叶子节点操作叶子节点与中间节点相似,除了其仅仅含有N个指针,执行N个关键字。 且我们在叶子节点的查找是属于精确查找,即查找出满足条件的关键字而非是查找出关键字所在的某个区域范围。 同样,我们可以使用与中间节点相似的办法来完成该项工作。连接处理 join processing algorithm嵌套循环连接作为处理连接操作的最简单的方式。其可以用来处理等式连接,也可以完成不等连接的处理。基本的操作方法在这里就不做详细讨论了。 使用simd技术,我们可以有三种处理嵌套循环的方法。 (1) 重复外循环的方式 duplicate-outer:在外循环中,我们取出一个外循环中的连接值 join key,并将其拷贝S份,因为我们SIMD每次处理的单元为S个。因此这样的处理,有利于一次处理内循环S个单元。 在内循环中,查找满足外循环条件的匹配值。(2)重复内循环方式 duplicate-outer:在外循环中取出S个连接key值,并将其构成一个SIMD单元。在内循环中,取出一个连接key并将其复制S份,并将这S个也构成一个SIMD单元。然后将这两个SIMD单元进行比较,当然这里是进行并行的方式。并根据比较的结果进行后续处理。(3)Rotate-Inner方式:在外循环中,取S个连接关键字,并将其构成一个SIMD单元,在内循环中,也取出S个并将其构成一个SIMD单元。将这两个SIMD单元进行比较S次,每次将内循环的单元rotate一个字的长度。并根据比较结果进行后续处理。对于简单的整数或者浮点数的连接谓词来说,SIMD算法叫传统的连接算法快上4倍左右。但在SIMD算法中仍然有相应的条件分支指令,而这将会导致40%的性能损耗。想了解更多精彩内容,请扫码关注【HW云数据库】公众号
-
本帖最后由 华为开源镜像站 于 2017-11-18 17:49 编辑Composer工作原理揭秘 基本用法[hr] [*]基本用法 [*]安装 [*]composer.json:项目安装 [*]关于 require Key [*]包名称 [*]包版本 [*]下一个重要版本(波浪号运算符) [*]稳定性 [*]安装依赖包 [*]composer.lock - 锁文件 [*]Packagist [*]自动加载 [hr] 安装安装 Composer,你只需要下载 composer.phar 可执行文件。curl -sS https://getcomposer.org/installer | php详细请查看 简介 章节。要检查 Composer 是否正常工作,只需要通过 php 来执行 PHAR:php composer.phar这将返回给你一个可执行的命令列表。[indent]注意: 你也可以仅执行 --check 选项而无需下载 Composer。 要获取更多的信息请使用 --help。curl -sS https://getcomposer.org/installer | php -- --help[/indent] composer.json:项目安装要开始在你的项目中使用 Composer,你只需要一个 composer.json 文件。该文件包含了项目的依赖和其它的一些元数据。这个 JSON format 是很容易编写的。它允许你定义嵌套结构。 关于 require Key第一件事情(并且往往只需要做这一件事),你需要在 composer.json 文件中指定 require key 的值。你只需要简单的告诉 Composer 你的项目需要依赖哪些包。[code]{ "require": { "monolog/monolog":"1.0.*" } }[/code] 你可以看到, require 需要一个 包名称 (例如 monolog/monolog) 映射到 包版本 (例如 1.0.*) 的对象。 包名称包名称由供应商名称和其项目名称构成。通常容易产生相同的项目名称,而供应商名称的存在则很好的解决了命名冲突的问题。它允许两个不同的人创建同样名为 json 的库,而之后它们将被命名为 igorw/json 和 seldaek/json。这里我们需要引入 monolog/monolog,供应商名称与项目的名称相同,对于一个具有唯一名称的项目,我们推荐这么做。它还允许以后在同一个命名空间添加更多的相关项目。如果你维护着一个库,这将使你可以很容易的把它分离成更小的部分。 包版本在前面的例子中,我们引入的 monolog 版本指定为 1.0.*。这表示任何从 1.0 开始的开发分支,它将会匹配 1.0.0、1.0.2 或者 1.0.20。版本约束可以用几个不同的方法来指定。名称实例描述确切的版本号1.0.2你可以指定包的确切版本。范围>=1.0 >=1.0,2.0>=1.0,1.1|>=1.2通过使用比较操作符可以指定有效的版本范围。 有效的运算符:>、>=、、=、!=。 你可以定义多个范围,用逗号隔开,这将被视为一个逻辑AND处理。一个管道符号|将作为逻辑OR处理。 AND 的优先级高于 OR。通配符1.0.*你可以使用通配符*来指定一种模式。1.0.*与>=1.0,1.1是等效的。赋值运算符~1.2这对于遵循语义化版本号的项目非常有用。~1.2相当于>=1.2,2.0。想要了解更多,请阅读下一小节。下一个重要版本(波浪号运算符)~ 最好用例子来解释: ~1.2 相当于 >=1.2,2.0,而 ~1.2.3 相当于 >=1.2.3,1.3。正如你所看到的这对于遵循 语义化版本号 的项目最有用。一个常见的用法是标记你所依赖的最低版本,像 ~1.2 (允许1.2以上的任何版本,但不包括2.0)。由于理论上直到2.0应该都没有向后兼容性问题,所以效果很好。你还会看到它的另一种用法,使用 ~ 指定最低版本,但允许版本号的最后一位数字上升。[indent]注意: 虽然 2.0-beta.1 严格地说是早于 2.0,但是,根据版本约束条件, 例如 ~1.2 却不会安装这个版本。就像前面所讲的 ~1.2 只意味着 .2 部分可以改变,但是 1. 部分是固定的。[/indent] 稳定性默认情况下只有稳定的发行版才会被考虑在内。如果你也想获得 RC、beta、alpha 或 dev 版本,你可以使用 稳定标志。你可以对所有的包做 最小稳定性 设置,而不是每个依赖逐一设置。 安装依赖包获取定义的依赖到你的本地项目,只需要调用 composer.phar 运行 install 命令。php composer.phar install接着前面的例子,这将会找到 monolog/monolog 的最新版本,并将它下载到 vendor 目录。 这是一个惯例把第三方的代码到一个指定的目录 vendor。如果是 monolog 将会创建 vendor/monolog/monolog 目录。[indent]小技巧: 如果你正在使用Git来管理你的项目, 你可能要添加 vendor 到你的 .gitignore 文件中。 你不会希望将所有的代码都添加到你的版本库中。[/indent]另一件事是 install 命令将创建一个 composer.lock 文件到你项目的根目录中。 composer.lock - 锁文件在安装依赖后,Composer 将把安装时确切的版本号列表写入 composer.lock 文件。这将锁定改项目的特定版本。请提交你应用程序的 composer.lock (包括 composer.json)到你的版本库中这是非常重要的,因为 install 命令将会检查锁文件是否存在,如果存在,它将下载指定的版本(忽略 composer.json 文件中的定义)。这意味着,任何人建立项目都将下载与指定版本完全相同的依赖。你的持续集成服务器、生产环境、你团队中的其他开发人员、每件事、每个人都使用相同的依赖,从而减轻潜在的错误对部署的影响。即使你独自开发项目,在六个月内重新安装项目时,你也可以放心的继续工作,即使从那时起你的依赖已经发布了许多新的版本。如果不存在 composer.lock 文件,Composer 将读取 composer.json 并创建锁文件。这意味着如果你的依赖更新了新的版本,你将不会获得任何更新。此时要更新你的依赖版本请使用 update 命令。这将获取最新匹配的版本(根据你的 composer.json 文件)并将新版本更新进锁文件。php composer.phar update如果只想安装或更新一个依赖,你可以白名单它们:php composer.phar update monolog/monolog [...][indent]注意: 对于库,并不一定建议提交锁文件 请参考:库的锁文件.[/indent] Packagistpackagist 是 Composer 的主要资源库。 一个 Composer 的库基本上是一个包的源:记录了可以得到包的地方。Packagist 的目标是成为大家使用库资源的中央存储平台。这意味着你可以 require 那里的任何包。当你访问 packagist website (packagist.org),你可以浏览和搜索资源包。任何支持 Composer 的开源项目应该发布自己的包在 packagist 上。虽然并不一定要发布在 packagist 上来使用 Composer,但它使我们的编程生活更加轻松。 自动加载对于库的自动加载信息,Composer 生成了一个 vendor/autoload.php 文件。你可以简单的引入这个文件,你会得到一个免费的自动加载支持。require ´vendor/autoload.php´;这使得你可以很容易的使用第三方代码。例如:如果你的项目依赖 monolog,你就可以像这样开始使用这个类库,并且他们将被自动加载。$log = new Monolog\Logger(´name´);$log-[color=rgb(166, 127, 89)>pushHandler(new Monolog\Handler\StreamHandler(´app.log´, Monolog\Logger::WARNING));$log-[color=rgb(166, 127, 89)>addWarning(´Foo´);你可以在 composer.json 的 autoload 字段中增加自己的 autoloader。 [code]{ "autoload": { "psr-4": { "Acme\\":"src/" } } }[/code] Composer 将注册一个 PSR-4 autoloader 到 Acme 命名空间。你可以定义一个从命名空间到目录的映射。此时 src 会在你项目的根目录,与 vendor 文件夹同级。例如 src/Foo.php 文件应该包含 Acme\Foo 类。添加 autoload 字段后,你应该再次运行 install 命令来生成 vendor/autoload.php 文件。引用这个文件也将返回 autoloader 的实例,你可以将包含调用的返回值存储在变量中,并添加更多的命名空间。这对于在一个测试套件中自动加载类文件是非常有用的,例如。$loader = require ´vendor/autoload.php´;$loader-[color=rgb(166, 127, 89)>add(´Acme\\Test\\´, __DIR__);除了 PSR-4 自动加载,classmap 也是支持的。这允许类被自动加载,即使不符合 PSR-0 规范。详细请查看 自动加载-参考。[indent]注意: Composer 提供了自己的 autoloader。如果你不想使用它,你可以仅仅引入 vendor/composer/autoload_*.php 文件,它返回一个关联数组,你可以通过这个关联数组配置自己的 autoloader。[/indent]
-
本帖最后由 yd_14752044 于 2017-10-27 10:37 编辑笔者认为做到比较优雅地编码,需遵从如下约束,排名分先后: [*]良好的命名 [*]清晰的结构 [*]不十分差劲的算法 下面逐一说明:良好的命名[indent][color=#**7]名不正,则言不顺,言不顺,则事不成 ── 孔子[/indent]孟子曰:“孔子说的对”。命名很重要,随便一本逻辑学教材(如果读者有兴趣,此处推荐《逻辑学导论》)里都会有长篇大论来讨论命名的问题,我国古代在人才辈出的百家争鸣时期曾经出现过一个学派叫“名家”,专门讨论命名的问题,比如著名的“白马非马”、“离坚白”等,有空读读还是挺有趣的,比玩王者荣耀还有趣。笔者认为我国到目前为止出现了三个思想大解放时期:一,春秋战国时期的百家争鸣,可惜被秦皇的郡县制大一统所终结;二,民国时期,西方思想初涌,国人似惊雷轰顶,如梦方醒;三,当下,技术革命使得中央思想控制力度急剧下降,使得底层人民有了选择被谁控制思想的自由(请参考如今基于互联网的粉丝文化,圈子文化)。所以大家一定要好好写代码,才不负少年头呀。回归主题,命名应该本着不怕长就怕不清楚的原则,尽量把一个类、方法、变量的含义交代清楚,实际上笔者比较喜欢OC的方法(消息)命名规则,比如:(void) buy:(NSString*)something from:(NSString*)store at:(NSDate*)time;长,但是很清楚。下面详述命名:接口的命名接口的命名一般都是前缀 I 加上名词或形容词,实际上.Net Framewrok类库就是这样做的,比如: [*]System.Collections.Generic.ICollection(名词) [*]System.Collections.Generic.IEnumerable(形容词) 接口往往用来分装一个或一组行为,实现接口的类意味着它具有了一个或一组行为的能力,所有常用形容词。当实在找不到一个恰当的形容词时,名词也可以。抽象类抽象类通常不需要加前缀或后缀,也有部分大牛喜欢给抽象类视情况加Base后缀。如下的命名笔者觉得就不错: [*]Shape(抽象类) [*]Ellipse(具体类) [*]Rectangle(具体类) 具体类尽量使用名词,不排除个别情况下把一个行为封装为类时使用动词。方法使用动词或动词性短语。以上。笔者觉得其它的字段啊、属性啊、事件啊出现命名问题的比较少,不再讨论。比如有的人喜欢字段用下划线开头,有的人喜欢用m_开头,都无关紧要,求同存异,只要使用的词语恰当,并不会带来太多麻烦。反倒是如果规定一个巨细无比的规范才有问题,一是耗费编撰者的时间,二是阅读者也记不住,三是阅读者记住了也可能因为和自己的习惯不同而心存抵触。此外需强调一点就是少用拼音多用英文,少用缩写多用全称,尽量不用拼音缩写,甚至是方言拼音缩写,还有英语加拼音,甚至是英语加拼音缩写......。但也不能排除个别如“计划生育”这样的不好翻译的词语可以用拼音,需注释明确或维护词汇表。另外,缩写也不是不可以用,一些大家约定成俗的缩写比如“Id”,使用之并不会带来误解,还有利于代码的清晰度。有时候由于英语水平的问题,毕竟我们的母语不是英语,难免会出现不知道用什么单词的情况。此时,可以试试codelf,感谢据说是网易工程师unbug开发的此工具。这个应该读作[koʊdɪf]吧,但是倒数第二个字母不是I,是L。清晰的结构基本要求 [*]if、while等关键字包裹的表达式,即使只有一句,也尽量使用大括号括起来 [*]尽量避免使用直立人时代的goto语句 [*]尽量避免过长的方法,把大方法拆分为数个小方法,方法的职能尽量单一 [*]尽量避免重复代码,将其转移到公共工具中 [*]尽量避免过大的类,拆分为数个类,各司其职 [*]适当的注释,注释太多,说明代码本身的表达力可能还有待加强。有些实在难缠的逻辑,可以写详细注释,如果不写注释,离职时请注意不要泄露给擦屁股人自己的地址 较高要求熟悉以下常用面向对象的设计原则: [*]开放-封闭 [*]单一职责 [*]里氏替换 [*]依赖倒置 [*]接口隔离 再高要求熟悉常用设计模式: [*]工厂方法 [*]抽象工厂 [*]建造者模式 [*]单例模式 [*]适配器模式 [*]外观模式 [*]观察者模式 [*]命令模式 [*]代理模式 [*]策略模式 面向对象语言的三大特征人人都知道,但是真的用好却是不容易,三大特征仅仅是面向对象设计的基础,在此基础上建立起了面向对象的高楼大厦。笔者工作多年,常感叹虚度年华,至今尚未精通面向对象设计之十之五六。笔者想极力推荐一本书:《Head First 设计模式》,此书乃Head First系列成名之作。此外,这个网站不错,言简意赅,案例经典:www.oodesign.com。此外,《Java编程思想》开头部分关于面向对象设计的讲解也很精彩。使用成熟的设计模式有两个好处: [*]这些解决方案已经经受过了考验,用了即使无功,但也不会犯错 [*]设计模式的名称本来就一种在程序员间流传的概念,基于共同的对概念的认识能够降低沟通成本 当然也有坏处,代码的扩展性虽然是好了,但是代码的复杂性也高了,这就要求我们最好熟悉常用的设计模式,这样就得到了它的好处,规避了它的坏处。必须要注意的是:不要乱用设计模式,只有需求产生了变化,或预见了需求将要发生变化才使用这些模式来封装发生的或可能发生的变化。有时候再重构代码时也会用到,比如外观模式和设配器模式等。更高要求[indent][color=#**7]能力越大,责任越大 ──蜘蛛侠[/indent]大项目肯定不是一个人能完成的,人多了容易发生混乱,此时需要团队的领袖勇敢地承担起义不容辞的责任,包括但不限于: [*]定期维护代码框架、分层结构。写的时间长了难免乱,领袖人物要定期排除,及时消除臭味 [*]引导小弟们做代码审查。审查的意义不在于监督,而在于学习和维持良好的态度。学习指通过代码审查学习别人的长处,同时帮助别人进步。保持良好的态度是指如果预知了有人会看自己的代码,那么就会自觉地尽量把代码写工整,即使审查代码的人偷懒没有真真看过,正所谓,如果人人都相信三尺之上有神灵,那么也就没人做坏事了,宗教的积极意义就在于此,扯远了。 [*]过目数据库设计 [*]及时更新或委派组员更新文档 关于文档,还需多说一句:只有再非常有必要写文档的情况下才写文档。如果写了一大堆可有可无的文档,代码更新后文档也要及时更新,很难做到的。一个新手面临着一堆和代码脱节的文档只会起误导作用,以代码本身的表达力和口头交流为主,以文档交流为辅,两手都要抓,一只手硬,一只手软。不十分差劲的算法相信大部人做的项目都是性能不敏感的,只要稍稍注意就能做好。比如该使用分页的地方就使用分页,该根据条件查询数据库的就别一次都查出来,该优化数据库就优化数据库。此外,压力测试也很有必要,有的性能问题只有在数据量大了的情况下才出现。很多性能问题都是到了生产环境中才暴漏出来的。代码之外和团队建设比起来,以上只能算是雕虫小技,只起到了一个锦上添花的作用。如何使团队保持活力,保持积极性才是最重要的,通常也是最容易被领导忽视的,最难做好的,这些已超出笔者能力范围和本文的论述重点,有机会再写。祝大家工作愉快!作文以记之丁酉年夏,鹏镇守武汉。数月,政通人和,百废俱兴,乃重修代码规范,属予作文以记之。予观博客园胜状,驼峰命名,强制注释,迫之芸芸码士,俱迂腐巨细之论,此前人之述备矣。然,求同存异,团队建设,收买人心,论之甚少,此大道也,得之可平天下。 来源:http://www.cnblogs.com/zzy0471/p/7236309.html
-
本帖最后由 小白 于 2017-9-27 11:32 编辑据美国哥伦比亚大学 CS 系报道,因在计算机历史方面的重大贡献,特别是 C++ 编程语言方面,C++ 之父 Bjarne Stroustrup 荣获 2017 年法拉第奖。 「法拉第奖」名字源于著名物理学家法拉第,1922 年由英国工程技术学(IET)设立的铜质奖章,用来授予在工程学上取得重大科技或工业成就,或为科学、工程和技术进步提供突出服务的个人。计算机科学家 Donald Knuth 曾获得 2011 年的法拉第奖。1978 年 Stroustrup 还在贝尔实验室时就开始开发 C++ 了。SIMULA 面向对象模型给了 C++ 很大影响,Stroustrup 在传统 C 语言基础上扩展增加了面向对象编程及其他功能。1985 年,C++ 商用发布并迅速蔓延,成为 20 世纪 90 年代占主导地位的面向对象编程语言。C++ 目前依然是一门最受欢迎的编程语言之一。Bjarne Stroustrup 将于 11 月 15 日前往伦敦出席颁奖典礼。 PS:为啥哥伦比亚大学 CS 系会报道这个消息?因为 Stroustrup 是他们系的客座教授。目前 Stroustrup 老爹是纽约摩根士丹利技术部的管理主任。
人生苦短,我用Python
发表于2017-09-27 10:21:29
2017-09-27 10:21:29
最后回复
人生苦短,我用Python
2017-09-27 10:21:29
3619 0
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签