• 关于

    伪随机数

    的搜索结果

回答

如果mysql有函数能做到,就用那函数吧。如果没有,就自己想个伪随机的解决方案吧。######你可以先在程序上随机几个数之后,直接在数据库里查询!非得在数据库里随机吗######select * from table limit m, n ,用程序随机m的值 ######楼上 方案 可行 ,不过还是有小缺陷 ,要获得总记录数 ,否则会超出范围,不赞成 用 mysql 随机函数 ###### 引用来自“fxhover”的答案 select * from table limit m, n ,用程序随机m的值 这性能不够好 ###### 引用来自“红星xx”的答案 楼上 方案 可行 ,不过还是有小缺陷 ,要获得总记录数 ,否则会超出范围,不赞成 用 mysql 随机函数 用mysql rand 性能太差,就是想换种方式得到同样的随机数。 ######mysql函数随机出来性能很差,最好的办法就是程序得到随机的数,去mysql取值###### 引用来自“sofire”的答案 如果mysql有函数能做到,就用那函数吧。如果没有,就自己想个伪随机的解决方案吧。 等于没说 ###### 引用来自“fzxu_05”的答案 mysql函数随机出来性能很差,最好的办法就是程序得到随机的数,去mysql取值 这方法是可行,现在想的是能不能直接用sql搞定,不用外面的程序得到随机数。 ###### 引用来自“huanlin08”的答案 引用来自“fzxu_05”的答案 mysql函数随机出来性能很差,最好的办法就是程序得到随机的数,去mysql取值 这方法是可行,现在想的是能不能直接用sql搞定,不用外面的程序得到随机数。 mysql有个rand的函数
kun坤 2020-06-09 22:39:59 0 浏览量 回答数 0

回答

但是,为了考虑到不出现极端情况,就需要改变一下。 魔兽争霸是这样做的:第一次是原概率,然后没有触发的话,第二次提升一点,还是没有触发就继续,直到一定会触发为止。这是为了防止出现极难触发的情况。 比如某个技能:A一下30%的概率暴击,那么第一下就是30%,没有暴击就提升一下,40%,再继续。直到触发为止,当然这个提升只是暂时的调整。 至于随机数,计算机目前还无法真正随机,基本都是伪随机,最好在每次随机时重新调整下随机数种子。 随机数判断很简单,比如1-100,随机出<=30的就可以认定触发了,而50%概率的技能,那么就是随机出<=50了,很简单。
杨冬芳 2019-12-02 03:01:06 0 浏览量 回答数 0

回答

如果是和安全相关的随机数,不要使用伪随机java.util.Random,而是java.security.SecureRandom。
有桥 2019-12-02 02:43:16 0 浏览量 回答数 0

回答

常见的Hash函数有以下几个: 直接定址法:直接以关键字k或者k加上某个常数(k+c)作为哈希地址。 数字分析法:提取关键字中取值比较均匀的数字作为哈希地址。 除留余数法:用关键字k除以某个不大于哈希表长度m的数p,将所得余数作为哈希表地址。 分段叠加法:按照哈希表地址位数将关键字分成位数相等的几部分,其中最后一部分可以比较短。然后将这几部分相加,舍弃最高进位后的结果就是该关键字的哈希地址。 平方取中法:如果关键字各个部分分布都不均匀的话,可以先求出它的平方值,然后按照需求取中间的几位作为哈希地址。 伪随机数法:采用一个伪随机数当作哈希函数。
huc_逆天 2021-01-08 14:35:21 0 浏览量 回答数 0

问题

数组中的加权随机选择

我想从数组中随机选择一个元素,但是每个元素都有一个已知的选择概率。 (在数组中)所有机会的总和为1。 您会建议哪种算法最快,最适合进行大量计算? 例:...
保持可爱mmm 2020-02-08 21:54:04 0 浏览量 回答数 1

问题

10万个数字无序排列,要求不重复

(PS:可能是我描述的不太清楚,其实意思就是这样的。依次生成10W个随机数填充到数组,随机数1-10W之间,不能重复。嗯,对,本意就是这样。)今天面试,技术总监给我出了个思考题,求随机10W个数字无序排列,如何才能高效的执行,内存没有要求,...
杨冬芳 2019-12-01 19:34:34 1083 浏览量 回答数 1

回答

可以采用32bit RSA算法 设A从2~(N-1) C=(A EXP D) mod N 满足如下条件: D是素数,N是两个素数(P,Q)之积, (D * E) mod ((P-1) * (Q-1))=1 因为:若 C=(A EXP D)mod N 有: A=(C EXP E) mod N 所以,C与A 一一对应。 所以,对于A=2~(N-1),有不重复,无遗漏的伪随机码C。 凡是稍微扯上一点数学,尤其是高等数学的问题,我等泛泛之辈看起来就有点费劲,这里虽然文字不长,但是还得慢慢来看。 这里面RSA算法是密码学三大算法之一(RSA、MD5、DES),是一种不对称密码算法。说如果满足条件:D是素数,N是两个素数(P,Q)之积,(D * E) mod ((P-1) * (Q-1))=1,那么存在C与A(范围从2到N-1)一一对应,且C=(A EXP D)mod N。A是一个有顺序的数,C就是一个看似无规律的伪随机数。Mod运算表示求模,例如7Mod3=1。意思是7除以3余1。类似地8Mod3=2,9Mod3=0。EXP表示前面数的后面数次方,AEXPD表示A的D次方。这两个运算清楚了,其它的也就没什么困难的了,*是乘法的意思,大多数理科生都清
管理贝贝 2019-12-02 01:26:24 0 浏览量 回答数 0

回答

1,生成 [ 0, 1 ) 范围内的随机数(大于等于0,小于1) (1)使用 random() 方法可以返回一个介于 0 ~ 1 之间的伪随机数(包括 0,不包括 1)。 Math.random() (2)下面是一个测试样例 var random = Math.random(); console.log(random); 2,生成 [ n, m ) 范围内的随机数(大于等于n,小于m) (1)这种最简单,因为和 random 的特点保持一致。只需使用如下公式即可: Math.random()*(m-n)+n (2)比如下面生成 [10,15) 范围内的随机浮点数。 var random1 = Math.random()*(15-10)+10; var random2 = Math.random()*(15-10)+10; var random3 = Math.random()*(15-10)+10; console.log(random1); console.log(random2); console.log(random3);
剑曼红尘 2020-04-03 15:11:15 0 浏览量 回答数 0

回答

递增的整数可以用在内部的服务中,如果用在外部,可能会泄漏信息,所以如果能产生随机数就可以解决这个问题。 当然直接生成随机数可能比较困难,你可以在递增的整数上产生伪随机的整数,比如使用skip32, 它还可以直接进行反解码,在内部反解出原来的递增的ID,所以在一些场景的也有广泛的应用,比如在Postgrepsql中可以实现skip32 function)。 另外一个比较常用的加密递增ID方法是hashid,它可以转换数字比如347为字符串yr8,并且还可以反解出来,提供了很多语言的实现,比如go-hashids、hashids-java、hashids.c等。 对于64 bit的整数,你可以使用Block ciphers实现加密。也有把64 bit整数分成两部分,分别应用skip32进行加密的。
kun坤 2020-04-23 19:10:03 0 浏览量 回答数 0

问题

求怎么输出多个伪随机数

int a[1000]; for(int b=0;b<1000;++b) { srand((int)time(0)); } for(int j=0;j<1000;j++) { a[b]=rand(); }...
a123456678 2019-12-01 20:06:49 779 浏览量 回答数 1

回答

这里有一个关于此类问题的非常有趣的讨论: http://www.titov.net/2005/09/21/do-not-use-order-by-rand-or-how-to-get-random-rows-from-table/ 我认为在没有任何假设的情况下,您的O(n lg n)解决方案是最好的。尽管实际上使用好的优化程序或稍有不同的技术,但您列出的查询可能会更好一些,O(m * n)其中m是所需的随机行数,因为它不必对整个大型数组进行排序,它可能只搜索最小的m次。但是对于您发布的那种数字,无论如何,m大于lg n。 我们可以尝试以下三种假设: 表中有一个唯一的,已索引的主键 您要选择的随机行数(m)比表中的行数(n)小得多 唯一主键是一个整数,范围是1到n,没有空格 仅假设1和2,我认为这可以在O(n)中完成,尽管您需要向表中写入一个完整的索引以匹配假设3,因此不一定需要快速的O(n)。如果我们可以另外假设该表有其他优点,则可以在O(m log m)中执行任务。假设3是一个易于使用的好属性。有了一个很好的随机数生成器,它可以保证在连续生成m个数时不会重复,因此O(m)解决方案是可能的。 给定这三个假设,基本思想是生成介于1和n之间的m个唯一的随机数,然后从表中选择具有这些键的行。我现在没有mysql或任何更新,所以在伪代码中看起来像这样: create table RandomKeys (RandomKey int) create table RandomKeysAttempt (RandomKey int) -- generate m random keys between 1 and n for i = 1 to m insert RandomKeysAttempt select rand()*n + 1 -- eliminate duplicates insert RandomKeys select distinct RandomKey from RandomKeysAttempt -- as long as we don't have enough, keep generating new keys, -- with luck (and m much less than n), this won't be necessary while count(RandomKeys) < m NextAttempt = rand()*n + 1 if not exists (select * from RandomKeys where RandomKey = NextAttempt) insert RandomKeys select NextAttempt -- get our random rows select * from RandomKeys r join table t ON r.RandomKey = t.UniqueKey 如果您真的担心效率,则可以考虑使用某种过程语言来生成随机密钥,并将结果插入数据库中,因为除SQL以外,几乎任何其他方法都可能在所需的循环和随机数生成方面更好。
保持可爱mmm 2019-12-02 03:17:25 0 浏览量 回答数 0

回答

桶排序算法要求,数据的长度必须完全一样,程序过程要产生长度相同的数据,使用下面的方法:Data=rand()/10000+10000上面提到的,每次下一次的扫描顺序是按照上次扫描的结果来的,所以设计上提供相同的两个桶数据结构。前一个保存每一次扫描的结果供下次调用,另外一个临时拷贝前一次扫描的结果提供给前一个调用。数据结构设计:链表可以采用很多种方式实现,通常的方法是动态申请内存建立结点,但是针对这个算法,桶里面的链表结果每次扫描后都不同,就有很多链表的分离和重建。如果使用动态分配内存,则由于指针的使用,安全性低。所以,笔者设计时使用了数组来模拟链表(当然牺牲了部分的空间,但是操作却是简单了很多,稳定性也大大提高了)。共十个桶,所以建立一个二维数组,行向量的下标0—9代表了10个桶,每个行形成的一维数组则是桶的空间。平均情况下桶排序以线性时间运行。像基数排序一样,桶排序也对输入作了某种假设, 因而运行得很快。具 体来说,基数排序假设输入是由一个小范围内的整数构成,而桶排序则 假设输入由一个随机过程产生,该过程将元素一致地分布在区间[0,1)上。 桶排序的思想就是把区间[0,1)划分成n个相同大小的子区间,或称桶,然后将n个输入数分布到各个桶中去。因为输入数均匀分布在[0,1)上,所以一般不会有很多数落在一个桶中的情况。为得到结果,先对各个桶中的数进行排序,然后按次序把各桶中的元素列出来即可。在桶排序算法的代码中,假设输入是含n个元素的数组A,且每个元素满足0≤ A[i]<1。另外还需要一个辅助数组B[O..n-1]来存放链表实现的桶,并假设可以用某种机制来维护这些表。桶排序的算法如下(伪代码表示),其中floor(x)是地板函数,表示不超过x的最大整数。procedure Bin_Sort(var A:List);beginn:=length(A);for i:=1 to n do将A[i]插到表B[floor(n*A[i])]中;for i:=0 to n-1 do用插入排序对表B[i]进行排序;将表B[0],B[1],...,B[n-1]按顺序合并;end;右图演示了桶排序作用于有10个数的输入数组上的操作过程。(a)输入数组A[1..10]。(b)在该算法的第5行后的有序表(桶)数组B[0..9]。桶i中存放了区间[i/10,(i+1)/10]上的值。排序输出由表B[O]、B[1]、...、B[9]的按序并置构成。要说明这个算法能正确地工作,看两个元素A[i]和A[j]。如果它们落在同一个桶中,则它们在输出序列中有着正确的相对次序,因为它们所在的桶是采用插入排序的。现假设它们落到不同的桶中,设分别为B[i']和B[j']。不失一般性,假设i' i'=floor(n*A[i])≥floor(n*A[j])=j' 得矛盾 (因为i' 来分析算法的运行时间。除第5行外,所有各行在最坏情况的时间都是O(n)。第5行中检查所有桶的时间是O(n)。分析中唯一有趣的部分就在于第5行中插人排序所花的时间。为分析插人排序的时间代价,设ni为表示桶B[i]中元素个数的随机变量。因为插入排序以二次时间运行,故为排序桶B[i]中元素的期望时间为E[O(ni2)]=O(E[ni2]),对各个桶中的所有元素排序的总期望时间为:O(n)。(1) 为了求这个和式,要确定每个随机变量ni的分布。我们共有n个元素,n个桶。某个元素落到桶B[i]的概率为l/n,因为每个桶对应于区间[0,1)的l/n。这种情况与投球的例子很类似:有n个球 (元素)和n个盒子 (桶),每次投球都是独立的,且以概率p=1/n落到任一桶中。这样,ni=k的概率就服从二项分布B(k;n,p),其期望值为E[ni]=np=1,方差V[ni]=np(1-p)=1-1/n。对任意随机变量X,有右图所示表达式。(2)将这个界用到(1)式上,得出桶排序中的插人排序的期望运行时间为O(n)。因而,整个桶排序的期望运行时间就是线性的。
liujae 2019-12-02 01:19:09 0 浏览量 回答数 0

回答

此问题包含两个非常不同的子问题: 该字符串看似必须是随机的 字符串必须唯一 尽管很容易实现随机性,但没有重试循环的唯一性却不容易。这使我们首先专注于独特性。使用可以轻松实现非随机唯一性AUTO_INCREMENT。因此,使用保留唯一性的伪随机转换就可以了: 哈希由@paul建议 AES加密也适合 但是有一个不错的:RAND(N)本身! 保证由同一种子创建的随机数序列是 可复制的 前8次迭代不同 如果种子是 INT32 因此,我们使用@AndreyVolk或@GordonLinoff的方法,但使用以下种子 RAND: 例如,Assumin id是一AUTO_INCREMENT列: INSERT INTO vehicles VALUES (blah); -- leaving out the number plate SELECT @lid:=LAST_INSERT_ID(); UPDATE vehicles SET numberplate=concat( substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@lid)*4294967296))*36+1, 1), substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1), substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1), substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1), substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1), substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1), substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1), substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed)*36+1, 1) ) WHERE id=@lid;来源:stack overflow
保持可爱mmm 2020-05-11 16:15:48 0 浏览量 回答数 0

回答

GPS都是不耗流量的,GPS是接受美国GPS卫星信号定位的,谁来计算你的流量。卫星。还是美国移动。GPS的话,就算SIM卡不放进手机,照样可以进行。 A-GPS(Assisted GPS)即辅助GPS技术,它可以提高 GPS 卫星定位系统的性能。通过移动通信运营基站它可以快速地定位,广泛用于含有GPS功能的手机上。 A-GPS由于需要基站辅助定位,因此是要消耗数据流量的。-------------------------乐phone启用A-GPS设置:进入系统设置-安全与定位设置-启用GPS卫星设置(A-GPS默认开启); 即使用导航时会产生流量; 如不想产生流量,导航时,直接进入系统设置-无线网络设置-关闭移动网络数据服务,启用GPS卫星设置不做操作即可; 导航过程中一般下载星历数据、基站辅助定位等都会产生流量; 定位精度:GPS=A-GPS>基站定位 定位速度:基站定位>A-GPS>GPS GPS原理 GPS 导航系统的基本原理是测量出已知位置的卫星到用户接收机之间的距离,然后综合多颗卫星的数据就可知道接收机的具体位置。要达到这一目的,卫星的位置可以根据星载时钟所记录的时间在卫星星历中查出。而用户到卫星的距离则通过纪录卫星信号传播到用户所经历的时间,再将其乘以光速得到(由于大气层电离层的干扰,这一距离并不是用户与卫星之间的真实距离,而是伪距(PR):当GPS卫星正常工作时,会不断地用1和0二进制码元组成的伪随机码(简称伪码)发射导航电文。GPS系统使用的伪码一共有两种,分别是民用的C/A码和军用的P(Y)码。C/A码频率1.023MHz,重复周期一毫秒,码间距1微秒,相当于 300m;P码频率10.23MHz,重复周期266.4天,码间距0.1微秒,相当于30m。而Y码是在P码的基础上形成的,保密性能更佳。导航电文包括卫星星历、工作状况、时钟改正、电离层时延修正、大气折射修正等信息。它是从卫星信号中解调制出来,以50b/s调制在载频上发射的。导航电文每个主帧中包含5个子帧每帧长6s。前三帧各10个字码;每三十秒重复一次,每小时更新一次。后两帧共15000b。导航电文中的内容主要有遥测码、转换码、第 1、2、3数据块,其中最重要的则为星历数据。当用户接受到导航电文时,提取出卫星时间并将其与自己的时钟做对比便可得知卫星与用户的距离,再利用导航电文中的卫星星历数据推算出卫星发射电文时所处位置,用户在WGS-84大地坐标系中的位置速度等信息便可得知。   可见GPS导航系统卫星部分的作用就是不断地发射导航电文。然而,由于用户接受机使用的时钟与卫星星载时钟不可能总是同步,所以除了用户的三维坐标x、y、z外,还要引进一个Δt即卫星与接收机之间的时间差作为未知数,然后用4个方程将这4个未知数解出来。所以如果想知道接收机所处的位置,至少要能接收到4个卫星的信号。   GPS接收机可接收到可用于授时的准确至纳秒级的时间信息;用于预报未来几个月内卫星所处概略位置的预报星历;用于计算定位时所需卫星坐标的广播星历,精度为几米至几十米(各个卫星不同,随时变化);以及GPS系统信息,如卫星状况等。   GPS接收机对码的量测就可得到卫星到接收机的距离,由于含有接收机卫星钟的误差及大气传播误差,故称为伪距。对0A码测得的伪距称为UA码伪距,精度约为20米左右,对P码测得的伪距称为P码伪距,精度约为2米左右。   GPS接收机对收到的卫星信号,进行解码或采用其它技术,将调制在载波上的信息去掉后,就可以恢复载波。严格而言,载波相位应被称为载波拍频相位,它是收到的受多普勒频移影响的卫星信号载波相位与接收机本机振荡产生信号相位之差。一般在接收机钟确定的历元时刻量测,保持对卫星信号的跟踪,就可记录下相位的变化值,但开始观测时的接收机和卫星振荡器的相位初值是不知道的,起始历元的相位整数也是不知道的,即整周模糊度,只能在数据处理中作为参数解算。相位观测值的精度高至毫米,但前提是解出整周模糊度,因此只有在相对定位、并有一段连续观测值时才能使用相位观测值,而要达到优于米级的定位 精度也只能采用相位观测值。   按定位方式,GPS定位分为单点定位和相对定位(差分定位)。单点定位就是根据一台接收机的观测数据来确定接收机位置的方式,它只能采用伪距观测量,可用于车船等的概略导航定位。相对定位(差分定位)是根据两台以上接收机的观测数据来确定观测点之间的相对位置的方法,它既可采用伪距观测量也可采用相位观测量,大地测量或工程测量均应采用相位观测值进行相对定位。   在GPS观测量中包含了卫星和接收机的钟差、大气传播延迟、多路径效应等误差,在定位计算时还要受到卫星广播星历误差的影响,在进行相对定位时大部分公共误差被抵消或削弱,因此定位精度将大大提高,双频接收机可以根据两个频率的观测量抵消大气中电离层误差的主要部分,在精度要求高,接收机间距离较远时(大气有明显差别),应选用双频接收机。 A-GPS原理 AGPS(AssistedGPS:辅助全球卫星定位系统)是结合GSM/GPRS与传统卫星定位,利用基地台代送辅助卫星信息,以缩减GPS芯片获取卫星信号的延迟时间,受遮盖的室内也能借基地台讯号弥补,减轻GPS芯片对卫星的依赖度。和纯GPS、基地台三角定位比较,AGPS能提供范围更广、更省电、速度更快的定位服务,理想误差范围在10公尺以内,日本和美国都已经成熟运用AGPS于LBS服务(locetionBasedService,适地性服务)。   AGPS技术是一种结合了网络基站信息和GPS信息对移动台进行定位的技术,可以在GSM/GPRS、WCDMA和CDMA2000网络中使用。该技术需要在手机内增加GPS接收机模块,并改造手机天线,同时要在移动网络上加建位置服务器、差分GPS基准站等设备。   AGPS解决方案的优势主要在首次捕获GPS信号的时间一般仅需几秒,不像GPS的首次捕获时间可能要2~3分钟。 基站定位原理   基站定位一般应用于手机用户,它是通过电信移动运营商的网络(如GSM网)获取移动终端用户的位置信息(经纬度坐标),在电子地图平台的支持下,为用户提供相应服务的一种增值业务,例如目前中国移动动感地带提供的动感位置查询服务等。其大致原理为:移动电话测量不同基站的下行导频信号,得到不同基站下行导频的TOA(Time of Arrival,到达时刻),根据该测量结果并结合基站的坐标,一般采用三角公式估计算法,就能够计算出移动电话的位置。实际的位置估计算法需要考虑多基站(3个或3个以上)定位的情况,因此算法要复杂很多。一般而言,移动台测量的基站数目越多,测量精度越高,定位性能改善越明显。
马铭芳 2019-12-02 01:16:50 0 浏览量 回答数 0

回答

    using System;     using System.Collections.Generic;     using System.Linq;     using System.Text;    namespace test{    class QuickSort    {        static void Main(string[] args)        {            int[] array = { 49, 38, 65, 97, 76, 13, 27 };            sort(array, 0, array.Length - 1);            Console.ReadLine();        }        /**一次排序单元,完成此方法,key左边都比key小,key右边都比key大。         **@param array排序数组          **@param low排序起始位置          **@param high排序结束位置         **@return单元排序后的数组 */        private static int sortUnit(int[] array, int low, int high)        {            int key = array[low];            while (low < high)            {                /*从后向前搜索比key小的值*/                while (array[high] >= key && high > low)                    --high;                 /*比key小的放左边*/                array[low] = array[high];                   /*从前向后搜索比key大的值,比key大的放右边*/                while (array[low] <= key && high > low)                    ++low;                 /*比key大的放右边*/                array[high] = array[low];            }            /*左边都比key小,右边都比key大。//将key放在游标当前位置。//此时low等于high */            array[low] = key;            foreach (int i in array)            {                Console.Write({0}\t, i);            }            Console.WriteLine();            return high;        }            /**快速排序 *@paramarry *@return */        public static void sort(int[] array, int low, int high)        {            if (low >= high)                return;             /*完成一次单元排序*/            int index = sortUnit(array, low, high);             /*对左边单元进行排序*/            sort(array, low, index - 1);            /*对右边单元进行排序*/            sort(array, index + 1, high);        }    }} 运行结果:27 38 13 49 76 97 6513 27 38 49 76 97 65  13 27 38 49 65 76 97快速排序就是递归调用此过程——在以49为中点分割这个数据序列,分别对前面一部分和后面一部分进行类似的快速排序,从而完成全部数据序列的快速排序,最后把此数据序列变成一个有序的序列,根据这种思想对于上述数组A的快速排序的全过程如图6所示:初始状态 {49 38 65 97 76 13 27} 进行一次快速排序之后划分为 {27 38 13} 49 {76 97 65} 分别对前后两部分进行快速排序{27 38 13} 经第三步和第四步交换后变成 {13 27 38} 完成排序。{76 97 65} 经第三步和第四步交换后变成 {65 76 97} 完成排序。图示 快速排序的最坏情况基于每次划分对主元的选择。基本的快速排序选取第一个元素作为主元。这样在数组已经有序的情况下,每次划分将得到最坏的结果。一种比较常见的优化方法是随机化算法,即随机选取一个元素作为主元。这种情况下虽然最坏情况仍然是O(n^2),但最坏情况不再依赖于输入数据,而是由于随机函数取值不佳。实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。所以随机化快速排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度。一位前辈做出了一个精辟的总结:“随机化快速排序可以满足一个人一辈子的人品需求。”随机化快速排序的唯一缺点在于,一旦输入数据中有很多的相同数据,随机化的效果将直接减弱。对于极限情况,即对于n个相同的数排序,随机化快速排序的时间复杂度将毫无疑问的降低到O(n^2)。解决方法是用一种方法进行扫描,使没有交换的情况下主元保留在原位置。 QUICKSORT(A,p,r)1 if p<r2 then q ←PARTITION(A,p,r)3 QUICKSORT(A,p,q-1)4 QUICKSORT(A,q+1,r)为排序一个完整的数组A,最初的调用是QUICKSORT(A,1,length[A])。快速排序算法的关键是PARTITION过程,它对子数组A[p..r]进行就地重排:PARTITION(A,p,r)1 x←A[r]2 i←p-13 for j←p to r-14 do if A[j]≤x5 then i←i+16 exchange A[i]←→A[j]7 exchange A[i+1]←→A[r]8 return i+1 对PARTITION和QUICKSORT所作的改动比较小。在新的划分过程中,我们在真正进行划分之前实现交换:(其中PARTITION过程同快速排序伪代码(非随机))RANDOMIZED-PARTITION(A,p,r)1 i← RANDOM(p,r)2 exchange A[r]←→A[i]3 return PARTITION(A,p,r)新的快速排序过程不再调用PARTITION,而是调用RANDOMIZED-PARTITION。RANDOMIZED-QUICKSORT(A,p,r)1 if p<r2 then q← RANDOMIZED-PARTITION(A,p,r)3 RANDOMIZED-QUICKSORT(A,p,q-1)4 RANDOMIZED-QUICKSORT(A,q+1,r) 这里为方便起见,我们假设算法Quick_Sort的范围阈值为1(即一直将线性表分解到只剩一个元素),这对该算法复杂性的分析没有本质的影响。我们先分析函数partition的性能,该函数对于确定的输入复杂性是确定的。观察该函数,我们发现,对于有n个元素的确定输入L[p..r],该函数运行时间显然为θ(n)。最坏情况无论适用哪一种方法来选择pivot,由于我们不知道各个元素间的相对大小关系(若知道就已经排好序了),所以我们无法确定pivot的选择对划分造成的影响。因此对各种pivot选择法而言,最坏情况和最好情况都是相同的。我们从直觉上可以判断出最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候(设输入的表有n个元素)。下面我们暂时认为该猜测正确,在后文我们再详细证明该猜测。对于有n个元素的表L[p..r],由于函数Partition的计算时间为θ(n),所以快速排序在序坏情况下的复杂性有递归式如下:T(1)=θ(1),T(n)=T(n-1)+T(1)+θ(n) (1)用迭代法可以解出上式的解为T(n)=θ(n2)。这个最坏情况运行时间与插入排序是一样的。下面我们来证明这种每次划分过程产生的两个区间分别包含n-1个元素和1个元素的情况就是最坏情况。设T(n)是过程Quick_Sort作用于规模为n的输入上的最坏情况的时间,则T(n)=max(T(q)+T(n-q))+θ(n),其中1≤q≤n-1 (2)我们假设对于任何k<n,总有T(k)≤ck,其中c为常数;显然当k=1时是成立的。将归纳假设代入(2),得到:T(n)≤max(cq2+c(n-q)2)+θ(n)=c*max(q2+(n-q)2)+θ(n)因为在[1,n-1]上q2+(n-q)2关于q递减,所以当q=1时q2+(n-q)2有最大值n2-2(n-1)。于是有:T(n)≤cn2-2c(n-1)+θ(n)≤cn2只要c足够大,上面的第二个小于等于号就可以成立。于是对于所有的n都有T(n)≤cn。这样,排序算法的最坏情况运行时间为θ(n2),且最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候。时间复杂度为o(n2)。最好情况如果每次划分过程产生的区间大小都为n/2,则快速排序法运行就快得多了。这时有:T(n)=2T(n/2)+θ(n),T(1)=θ(1) (3)解得:T(n)=θ(nlogn)快速排序法最佳情况下执行过程的递归树如下图所示,图中lgn表示以10为底的对数,而本文中用logn表示以2为底的对数.由于快速排序法也是基于比较的排序法,其运行时间为Ω(nlogn),所以如果每次划分过程产生的区间大小都为n/2,则运行时间θ(nlogn)就是最好情况运行时间。但是,是否一定要每次平均划分才能达到最好情况呢。要理解这一点就必须理解对称性是如何在描述运行时间的递归式中反映的。我们假设每次划分过程都产生9:1的划分,乍一看该划分很不对称。我们可以得到递归式:T(n)=T(n/10)+T(9n/10)+θ(n),T(1)=θ(1) (4)请注意树的每一层都有代价n,直到在深度log10n=θ(logn)处达到边界条件,以后各层代价至多为n。递归于深度log10/9n=θ(logn)处结束。这样,快速排序的总时间代价为T(n)=θ(nlogn),从渐进意义上看就和划分是在中间进行的一样。事实上,即使是99:1的划分时间代价也为θ(nlogn)。其原因在于,任何一种按常数比例进行划分所产生的递归树的深度都为θ(nlogn),其中每一层的代价为O(n),因而不管常数比例是什么,总的运行时间都为θ(nlogn),只不过其中隐含的常数因子有所不同。(关于算法复杂性的渐进阶,请参阅算法的复杂性)平均情况快速排序的平均运行时间为θ(nlogn)。我们对平均情况下的性能作直觉上的分析。要想对快速排序的平均情况有个较为清楚的概念,我们就要对遇到的各种输入作个假设。通常都假设输入数据的所有排列都是等可能的。后文中我们要讨论这个假设。当我们对一个随机的输入数组应用快速排序时,要想在每一层上都有同样的划分是不太可能的。我们所能期望的是某些划分较对称,另一些则很不对称。事实上,我们可以证明,如果选择L[p..r]的第一个元素作为支点元素,Partition所产生的划分80%以上都比9:1更对称,而另20%则比9:1差,这里证明从略。平均情况下,Partition产生的划分中既有“好的”,又有“差的”。这时,与Partition执行过程对应的递归树中,好、差划分是随机地分布在树的各层上的。为与我们的直觉相一致,假设好、差划分交替出现在树的各层上,且好的划分是最佳情况划分,而差的划分是最坏情况下的划分。在根节点处,划分的代价为n,划分出来的两个子表的大小为n-1和1,即最坏情况。在根的下一层,大小为n-1的子表按最佳情况划分成大小各为(n-1)/2的两个子表。这儿我们假设含1个元素的子表的边界条件代价为1。在一个差的划分后接一个好的划分后,产生出三个子表,大小各为1,(n-1)/2和(n-1)/2,代价共为2n-1=θ(n)。一层划分就产生出大小为(n-1)/2+1和(n-1)/2的两个子表,代价为n=θ(n)。这种划分差不多是完全对称的,比9:1的划分要好。从直觉上看,差的划分的代价θ(n)可被吸收到好的划分的代价θ(n)中去,结果是一个好的划分。这样,当好、差划分交替分布划分都是好的一样:仍是θ(nlogn),但θ记号中隐含的常数因子要略大一些。关于平均情况的严格分析将在后文给出。在前文从直觉上探讨快速排序的平均性态过程中,我们已假定输入数据的所有排列都是等可能的。如果输入的分布满足这个假设时,快速排序是对足够大的输入的理想选择。但在实际应用中,这个假设就不会总是成立。解决的方法是,利用随机化策略,能够克服分布的等可能性假设所带来的问题。一种随机化策略是:与对输入的分布作“假设”不同的是对输入的分布作“规定”。具体地说,在排序输入的线性表前,对其元素加以随机排列,以强制的方法使每种排列满足等可能性。事实上,我们可以找到一个能在O(n)时间内对含n个元素的数组加以随机排列的算法。这种修改不改变算法的最坏情况运行时间,但它却使得运行时间能够独立于输入数据已排序的情况。另一种随机化策略是:利用前文介绍的选择支点元素pivot的第四种方法,即随机地在L[p..r]中选择一个元素作为支点元素pivot。实际应用中通常采用这种方法。快速排序的随机化版本有一个和其他随机化算法一样的有趣性质:没有一个特别的输入会导致最坏情况性态。这种算法的最坏情况性态是由随机数产生器决定的。你即使有意给出一个坏的输入也没用,因为随机化排列会使得输入数据的次序对算法不产生影响。只有在随机数产生器给出了一个很不巧的排列时,随机化算法的最坏情况性态才会出现。事实上可以证明几乎所有的排列都可使快速排序接近平均情况性态,只有非常少的几个排列才会导致算法的近最坏情况性态。一般来说,当一个算法可按多条路子做下去,但又很难决定哪一条保证是好的选择时,随机化策略是很有用的。如果大部分选择都是好的,则随机地选一个就行了。通常,一个算法在其执行过程中要做很多选择。如果一个好的选择的获益大于坏的选择的代价,那么随机地做一个选择就能得到一个很有效的算法。我们在前文已经了解到,对快速排序来说,一组好坏相杂的划分仍能产生很好的运行时间 。因此我们可以认为该算法的随机化版本也能具有较好的性态。
liujae 2019-12-02 01:18:45 0 浏览量 回答数 0

问题

【算法】五分钟算法小知识:洗牌算法

我知道大家会各种花式排序,但是如果叫你打乱一个数组,你是否能做到胸有成竹?即便你拍脑袋想出一个算法,怎么证明你的算法就是正确的呢?乱序算法不像排序算法,结果...
游客ih62co2qqq5ww 2020-05-06 13:22:45 11 浏览量 回答数 1

回答

token是用于跨域和跨连接/会话的一种权限认证方式。 而你本地破解泄露是属于本地漏洞。 这是两码事。 混在一块考虑没有意义。 ###### 我觉得没有办法   最多复杂化求解  想了几种方式  均告失败 1  对token进行对称加密   密钥发送给服务器   使用时  请求服务器获取密钥  解密    漏洞   盗窃者也可以请求服务器获取密钥  解密 2   client端和server端共同维护一个字符表  client端得到的token在表中的序列值  使用时  根据序列值还原token     漏洞   盗窃者可以破解该表 ###### 3    token定期失效   要求用户重新登入       漏洞   token有效期内问题依然存在   同时会导致用户体验不佳 ###### 引用来自“张山疯”的评论 token是用于跨域和跨连接/会话的一种权限认证方式。 而你本地破解泄露是属于本地漏洞。 这是两码事。 混在一块考虑没有意义。 谢谢科普  不过我的问题你没有回答 我是问  在移动应用领域  如何有效的保护用户数据  说token只是一个引子  希望大家能更好的理解  谢谢 ###### 1. token 与本地IP,或者user agent做关联,具体可以取如手机硬件参数等,这样可以防止拿token到其它地方用的问题,但还是不能解决全部,因为理论上来说,客户端所有东西都可以伪造成和原来的一模一样 2. 就是对于一些敏感操作,如转帐,改密等,需要进行密码或者令牌的二次确认 ######不要明文发,在本地通过一定的规则加密后再发。######拿到ROOT权限 就不安全了 问题里提到的手机淘宝案例 你可以看看######  我也有这样的困惑。 有什么好的建议么? 上HTTPS 也不是一个绝对保险的办法###### 引用来自“shijacky”的评论 token 与本地IP,或者user agent做关联,具体可以取如手机硬件参数等,这样可以防止拿token到其它地方用的问题,但还是不能解决全部,因为理论上来说,客户端所有东西都可以伪造成和原来的一模一样就是对于一些敏感操作,如转帐,改密等,需要进行密码或者令牌的二次确认 1   漏洞   盗窃都也可以获取本地IP  use agent等相关数据   再通过分析apk代码  解密 2   这是一个好方法   不过此处只讨论没有第三方输入的情况 ###### 昨晚灵泉涌现   想到一个解决方案   早上来不及洗刷   电脑一查  果然OK 4   client端获取token后   通过native代码获取app签名文件内容   此处指android  app打包时的签名文件  ios wp8请自行对照  结合token+签名内容+S  使用公钥加密后发送给server端验证  OK     漏洞  无 签名文件内容必须在app运行之后才可以得到  分析apk原文件无法得到    注   S为随机数  server端维护 ######回复 @欣儿 : 是的 所以下面我评论了 本来我以为这个内容第三方获取不到 既然能获取就没有意义了 这个方案里的内容 必须要满足私有 值固定 系统级 才可行######这个,还是可以破解吧,安卓的可以获取运行时数据,就是说,只要运行,签名这些也可以得到######果然是我高兴的太早 经过验证 第三方同样可以通过native代码获取签名内容 所以这个方案存在漏洞######我记得是:签名是可以通过apk 的pakageInfo获取到的。如果查询所有的安装包的签名信息,找出包名一样的签名信息。会不会就破解了呢?######你说的签名文件内容是什么?sha1?######家门钥匙丢了,自己却不知道,此时如何防盗?######你这个比喻不恰当 client和server的通信 是联机操作 不是单机操作 单机操作当然没有安全可言
kun坤 2020-06-05 14:25:22 0 浏览量 回答数 0

回答

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 [编辑本段]基本概念 * 若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数(Hash function),按这个思想建立的表为散列表。 * 对不同的关键字可能得到同一散列地址,即key1≠key2,而f(key1)=f(key2),这种现象称冲突。具有相同函数值的关键字对该散列函数来说称做同义词。综上所述,根据散列函数H(key)和处理冲突的方法将一组关键字映象到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“象” 作为记录在表中的存储位置,这种表便称为散列表,这一映象过程称为散列造表或散列,所得的存储位置称散列地址。 * 若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个“随机的地址”,从而减少冲突。 [编辑本段]常用的构造散列函数的方法 散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位ǐ 1. 直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a•key + b,其中a和b为常数(这种散列函数叫做自身函数) 2. 数字分析法 3. 平方取中法 4. 折叠法 5. 随机数法 6. 除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。 [编辑本段]处理冲突的方法 1. 开放寻址法:Hi=(H(key) + di) MOD m, i=1,2,…, k(k<=m-1),其中H(key)为散列函数,m为散列表长,di为增量序列,可有下列三种取法: 1. di=1,2,3,…, m-1,称线性探测再散列; 2. di=1^2, (-1)^2, 2^2,(-2)^2, (3)^2, …, ±(k)^2,(k<=m/2)称二次探测再散列; 3. di=伪随机数序列,称伪随机探测再散列。 == 2. 再散列法:Hi=RHi(key), i=1,2,…,k RHi均是不同的散列函数,即在同义词产生地址冲突时计算另一个散列函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但增加了计算时间。 3. 链地址法(拉链法) 4. 建立一个公共溢出区 [编辑本段]查找的性能分析 散列表的查找过程基本上和造表过程相同。一些关键码可通过散列函数转换的地址直接找到,另一些关键码在散列函数得到的地址上产生了冲突,需要按处理冲突的方法进行查找。在介绍的三种处理冲突的方法中,产生冲突后的查找仍然是给定值与关键码进行比较的过程。所以,对散列表查找效率的量度,依然用平均查找长度来衡量。 查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。因此,影响产生冲突多少的因素,也就是影响查找效率的因素。影响产生冲突多少有以下三个因素: 1. 散列函数是否均匀; 2. 处理冲突的方法; 3. 散列表的装填因子。 散列表的装填因子定义为:α= 填入表中的元素个数 / 散列表的长度 α是散列表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。 实际上,散列表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数。 了解了hash基本定义,就不能不提到一些著名的hash算法,MD5 和 SHA-1 可以说是目前应用最广泛的Hash算法,而它们都是以 MD4 为基础设计的。那么他们都是什么意思呢? 这里简单说一下: (1) MD4 MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现--它是基于 32 位操作数的位操作来实现的。 (2) MD5 MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好 (3) SHA-1 及其他 SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。 那么这些Hash算法到底有什么用呢? Hash算法在信息安全方面的应用主要体现在以下的3个方面: (1) 文件校验 我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。 MD5 Hash算法的"数字指纹"特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。 (2) 数字签名 Hash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色。 对 Hash 值,又称"数字摘要"进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点。 (3) 鉴权协议 如下的鉴权协议又被称作挑战--认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。 MD5、SHA1的破解 2004年8月17日,在美国加州圣芭芭拉召开的国际密码大会上,山东大学王小云教授在国际会议上首次宣布了她及她的研究小组近年来的研究成果——对MD5、HAVAL-128、MD4和RIPEMD等四个著名密码算法的破译结果。 次年二月宣布破解SHA-1密码。 [编辑本段]实际应用 以上就是一些关于hash以及其相关的一些基本预备知识。那么在emule里面他具体起到什么作用呢? 大家都知道emule是基于P2P (Peer-to-peer的缩写,指的是点对点的意思的软件), 它采用了"多源文件传输协议”(MFTP,the Multisource FileTransfer Protocol)。在协议中,定义了一系列传输、压缩和打包还有积分的标准,emule 对于每个文件都有md5-hash的算法设置,这使得该文件独一无二,并且在整个网络上都可以追踪得到。 什么是文件的hash值呢? MD5-Hash-文件的数字文摘通过Hash函数计算得到。不管文件长度如何,它的Hash函数计算结果是一个固定长度的数字。与加密算法不同,这一个Hash算法是一个不可逆的单向函数。采用安全性高的Hash算法,如MD5、SHA时,两个不同的文件几乎不可能得到相同的Hash结果。因此,一旦文件被修改,就可检测出来。 当我们的文件放到emule里面进行共享发布的时候,emule会根据hash算法自动生成这个文件的hash值,他就是这个文件唯一的身份标志,它包含了这个文件的基本信息,然后把它提交到所连接的服务器。当有他人想对这个文件提出下载请求的时候, 这个hash值可以让他人知道他正在下载的文件是不是就是他所想要的。尤其是在文件的其他属性被更改之后(如名称等)这个值就更显得重要。而且服务器还提供了,这个文件当前所在的用户的地址,端口等信息,这样emule就知道到哪里去下载了。 一般来讲我们要搜索一个文件,emule在得到了这个信息后,会向被添加的服务器发出请求,要求得到有相同hash值的文件。而服务器则返回持有这个文件的用户信息。这样我们的客户端就可以直接的和拥有那个文件的用户沟通,看看是不是可以从他那里下载所需的文件。 对于emule中文件的hash值是固定的,也是唯一的,它就相当于这个文件的信息摘要,无论这个文件在谁的机器上,他的hash值都是不变的,无论过了多长时间,这个值始终如一,当我们在进行文件的下载上传过程中,emule都是通过这个值来确定文件。 那么什么是userhash呢? 道理同上,当我们在第一次使用emule的时候,emule会自动生成一个值,这个值也是唯一的,它是我们在emule世界里面的标志,只要你不卸载,不删除config,你的userhash值也就永远不变,积分制度就是通过这个值在起作用,emule里面的积分保存,身份识别,都是使用这个值,而和你的id和你的用户名无关,你随便怎么改这些东西,你的userhash值都是不变的,这也充分保证了公平性。其实他也是一个信息摘要,只不过保存的不是文件信息,而是我们每个人的信息。 那么什么是hash文件呢? 我们经常在emule日志里面看到,emule正在hash文件,这里就是利用了hash算法的文件校验性这个功能了,文章前面已经说了一些这些功能,其实这部分是一个非常复杂的过程,目前在ftp,bt等软件里面都是用的这个基本原理,emule里面是采用文件分块传输,这样传输的每一块都要进行对比校验,如果错误则要进行重新下载,这期间这些相关信息写入met文件,直到整个任务完成,这个时候part文件进行重新命名,然后使用move命令,把它传送到incoming文件里面,然后met文件自动删除,所以我们有的时候会遇到hash文件失败,就是指的是met里面的信息出了错误不能够和part文件匹配,另外有的时候开机也要疯狂hash,有两种情况一种是你在第一次使用,这个时候要hash提取所有文件信息,还有一种情况就是上一次你非法关机,那么这个时候就是要进行排错校验了。 关于hash的算法研究,一直是信息科学里面的一个前沿,尤其在网络技术普及的今天,他的重要性越来越突出,其实我们每天在网上进行的信息交流安全验证,我们在使用的操作系统密钥原理,里面都有它的身影,特别对于那些研究信息安全有兴趣的朋友,这更是一个打开信息世界的钥匙,他在hack世界里面也是一个研究的焦点。 一般的线性表、树中,记录在结构中的相对位置是随机的即和记录的关键字之间不存在确定的关系,在结构中查找记录时需进行一系列和关键字的比较。这一类查找方法建立在“比较”的基础上,查找的效率与比较次数密切相关。理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。因而查找时,只需根据这个对应关系f找到给定值K的像f(K)。若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上,由此不需要进行比较便可直接取得所查记录。在此,称这个对应关系f为哈希函数,按这个思想建立的表为哈希表(又称为杂凑法或散列表)。 哈希表不可避免冲突(collision)现象:对不同的关键字可能得到同一哈希地址 即key1≠key2,而hash(key1)=hash(key2)。具有相同函数值的关键字对该哈希函数来说称为同义词(synonym)。 因此,在建造哈希表时不仅要设定一个好的哈希函数,而且要设定一种处理冲突的方法。可如下描述哈希表:根据设定的哈希函数H(key)和所选中的处理冲突的方法,将一组关键字映象到一个有限的、地址连续的地址集(区间)上并以关键字在地址集中的“象”作为相应记录在表中的存储位置,这种表被称为哈希表。 对于动态查找表而言,1) 表长不确定;2)在设计查找表时,只知道关键字所属范围,而不知道确切的关键字。因此,一般情况需建立一个函数关系,以f(key)作为关键字为key的录在表中的位置,通常称这个函数f(key)为哈希函数。(注意:这个函数并不一定是数学函数) 哈希函数是一个映象,即:将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地址集合的大小不超出允许范围即可。 现实中哈希函数是需要构造的,并且构造的好才能使用的好。 用途:加密,解决冲突问题。。。。 用途很广,比特精灵中就使用了哈希函数,你可 以自己看看。 具体可以学习一下数据结构和算法的书。 [编辑本段]字符串哈希函数 (著名的ELFhash算法) int ELFhash(char *key) return h%MOD; }
晚来风急 2019-12-02 01:22:24 0 浏览量 回答数 0

问题

【javascript学习全家桶】934道javascript热门问题,阿里百位技术专家答疑解惑

阿里极客公益活动:或许你挑灯夜战只为一道难题或许你百思不解只求一个答案或许你绞尽脑汁只因一种未知那么他们来了,阿里系技术专家来云栖问答为你解答技术难题了他们用户自己手中的技术来帮助用户成长本次活动特邀百位阿里技术专家对javascript常...
管理贝贝 2019-12-01 20:07:22 6202 浏览量 回答数 1

回答

. 在编写一个类时,如果该类中的代码可能运行与多线程环境下,就要考虑同步问题了。 会同时被多个线程访问的资源,就是竞争资源,也称为竞争条件。对于多线程共享的资源我们必须进行同步,以避免一个线程的改动被另一个线程所覆盖。 synchronized 关键字有两种作用域: 1> 某个对象实例内,synchronized aMethod(){}关键字可以防止多个线程访问对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法. 2> 是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。 synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法; Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。      一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。      二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。      三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。      四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部   分的访问都被暂时阻塞。      五、以上规则对其它对象锁同样适用. 2. synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。   synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:   synchronized void accessVal(int newVal);   synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能 执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行 状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有 一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized) 。  在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成 员变量的访问。  synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可 以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供 了更好的解决办法,那就是 synchronized 块。   synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:  synchronized(syncObject) {   //允许访问控制的代码  }  synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机 制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。  对synchronized(this)的一些理解 一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线 程必须等待当前线程执行完这个代码块以后才能执行该代码块。  二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized (this)同步代码块。  三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this) 同步代码块的访问将被阻塞。  四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个 object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。  五、以上规则对其它对象锁同样适用 3.打个比方:一个object就像一个大房子,大门永远打开。房子里有 很多房间(也就是方法)。 这些房间有上锁的(synchronized方法), 和不上锁之分(普通方法)。房门口放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。 另外我把所有想调用该对象方法的线程比喻成想进入这房子某个 房间的人。所有的东西就这么多了,下面我们看看这些东西之间如何作用的。 在此我们先来明确一下我们的前提条件。该对象至少有一个synchronized方法,否则这个key还有啥意义。当然也就不会有我们的这个主题了。 一个人想进入某间上了锁的房间,他来到房子门口,看见钥匙在那儿(说明暂时还没有其他人要使用上锁的 房间)。于是他走上去拿到了钥匙 ,并且按照自己 的计划使用那些房间。注意一点,他每次使用完一次上锁的房间后会马上把钥匙还回去。即使他要连续使用两间上锁的房间, 中间他也要把钥匙还回去,再取回来。 因此,普通情况下钥匙的使用原则是:“随用随借,用完即还。” 这时其他人可以不受限制的使用那些不上锁的房间,一个人用一间可以,两个人用一间也可以,没限制。但是如果当某个人想要进入上锁的房 间,他就要跑到大门口去看看了。有钥匙当然拿了就走,没有的话,就只能等了。 要是很多人在等这把钥匙,等钥匙还回来以后,谁会优先得到钥匙?Not guaranteed。象前面例子里那个想连续使用两个上锁房间的家伙,他 中间还钥匙的时候如果还有其他人在等钥匙,那么没有任何保证这家伙能再次拿到。 (JAVA规范在很多地方都明确说明不保证,象 Thread.sleep()休息后多久会返回运行,相同优先权的线程那个首先被执行,当要访问对象的锁被 释放后处于等待池的多个线程哪个会优先得 到,等等。我想最终的决定权是在JVM,之所以不保证,就是因为JVM在做出上述决定的时候,绝不是简简单单根据 一个条件来做出判断,而是 根据很多条。而由于判断条件太多,如果说出来可能会影响JAVA的推广,也可能是因为知识产权保护的原因吧。SUN给了个不保证 就混过去了 。无可厚非。但我相信这些不确定,并非完全不确定。因为计算机这东西本身就是按指令运行的。即使看起来很随机的现象,其实都是有规律 可寻。学过 计算机的都知道,计算机里随机数的学名是伪随机数,是人运用一定的方法写出来的,看上去随机罢了。另外,或许是因为要想弄 的确定太费事,也没多大意义,所 以不确定就不确定了吧。) 再来看看同步代码块。和同步方法有小小的不同。 1.从尺寸上讲,同步代码块比同步方法小。你可以把同步代码块看成是没上锁房间里的一块用带锁的屏风隔开的空间。 2.同步代码块还可以人为的指定获得某个其它对象的key。就像是指定用哪一把钥匙才能开这个屏风的锁,你可以用本房的钥匙;你也可以指定 用另一个房子的钥匙才能开,这样的话,你要跑到另一栋房子那儿把那个钥匙拿来,并用那个房子的钥匙来打开这个房子的带锁的屏风。          记住你获得的那另一栋房子的钥匙,并不影响其他人进入那栋房子没有锁的房间。          为什么要使用同步代码块呢?我想应该是这样的:首先对程序来讲同步的部分很影响运行效率,而一个方法通常是先创建一些局部变 量,再对这些变量做一些 操作,如运算,显示等等;而同步所覆盖的代码越多,对效率的影响就越严重。因此我们通常尽量缩小其影响范围。 如何做?同步代码块。我们只把一个方法中该同 步的地方同步,比如运算。          另外,同步代码块可以指定钥匙这一特点有个额外的好处,是可以在一定时期内霸占某个对象的key。还记得前面说过普通情况下钥 匙的使用原则吗。现在不是普通情况了。你所取得的那把钥匙不是永远不还,而是在退出同步代码块时才还。           还用前面那个想连续用两个上锁房间的家伙打比方。怎样才能在用完一间以后,继续使用另一间呢。用同步代码块吧。先创建另外 一个线程,做一个同步代码 块,把那个代码块的锁指向这个房子的钥匙。然后启动那个线程。只要你能在进入那个代码块时抓到这房子的钥匙 ,你就可以一直保留到退出那个代码块。也就是说 你甚至可以对本房内所有上锁的房间遍历,甚至再sleep(10601000),而房门口却还有 1000个线程在等这把钥匙呢。很过瘾吧。           在此对sleep()方法和钥匙的关联性讲一下。一个线程在拿到key后,且没有完成同步的内容时,如果被强制sleep()了,那key还一 直在 它那儿。直到它再次运行,做完所有同步内容,才会归还key。记住,那家伙只是干活干累了,去休息一下,他并没干完他要干的事。为 了避免别人进入那个房间 把里面搞的一团糟,即使在睡觉的时候他也要把那唯一的钥匙戴在身上。           最后,也许有人会问,为什么要一把钥匙通开,而不是一个钥匙一个门呢?我想这纯粹是因为复杂性问题。一个钥匙一个门当然更 安全,但是会牵扯好多问题。钥匙 的产生,保管,获得,归还等等。其复杂性有可能随同步方法的增加呈几何级数增加,严重影响效率。这也 算是一个权衡的问题吧。为了增加一点点安全性,导致效 率大大降低,是多么不可取啊。 synchronized的一个简单例子 public class TextThread { public static void main(String[] args) {    TxtThread tt = new TxtThread();    new Thread(tt).start();    new Thread(tt).start();    new Thread(tt).start();    new Thread(tt).start(); } } class TxtThread implements Runnable { int num = 100; String str = new String(); public void run() {    synchronized (str) {     while (num > 0) {      try {       Thread.sleep(1);      } catch (Exception e) {       e.getMessage();      }      System.out.println(Thread.currentThread().getName()        + "this is " + num--);     }    } } } 上面的例子中为了制造一个时间差,也就是出错的机会,使用了Thread.sleep(10) Java对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。到底如 何?――还得对synchronized关键字的作用进行深入了解才可定论。 总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类, synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。 在进一步阐述之前,我们需要明确几点: A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其 他线程的对象访问。 B.每个对象只有一个锁(lock)与之相关联。 C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。 接着来讨论synchronized用到不同地方对代码产生的影响: 假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。 1. 把synchronized当作函数修饰符时,示例代码如下: Public synchronized void methodAAA() { //…. } 这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中 执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了 synchronized关键字的方法。 上边的示例代码等同于如下代码: public void methodAAA() { synchronized (this)      // (1) {        //….. } } (1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。――那个 拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造 成数据混乱:( 2.同步块,示例代码如下: public void method3(SomeObject so) {     synchronized(so)     {        //…..     } } 这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明 确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁: class Foo implements Runnable {         private byte[] lock = new byte[0]; // 特殊的instance变量         Public void methodA()         {            synchronized(lock) { //… }         }         //….. } 注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。 3.将synchronized作用于static 函数,示例代码如下: Class Foo {     public synchronized static void methodAAA()   // 同步的static 函数     {         //….     }     public void methodBBB()     {        synchronized(Foo.class)   // class literal(类名称字面常量)     } }    代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这 个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。 记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样,不能用P1.getClass()来达到锁这个Class的 目的。P1指的是由Foo类产生的对象。 可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj 在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。 小结如下: 搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。 还有一些技巧可以让我们对共享资源的同步访问更加安全: 1. 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以 绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。 2. 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象 的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并 且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了 作者:hanwei_java 来源:CSDN 原文:https://blog.csdn.net/hanwei_java/article/details/79738614 版权声明:本文为博主原创文章,转载请附上博文链接!
auto_answer 2019-12-02 01:50:26 0 浏览量 回答数 0

回答

adb介绍: Android Debug Bridge(安卓调试桥) tools。它就是一个命令行窗口,用于通过电脑端与模拟器或者是设备之间的交互。 ADB是一个C/S架构的应用程序,由三部分组成: 运行在pc端的adb client: 命令行程序”adb”用于从shell或脚本中运行adb命令。首先,“adb”程序尝试定位主机上的ADB服务器,如果找不到ADB服务器,“adb”程序自动启动一个ADB服务器。接下来,当设备的adbd和pc端的adb server建立连接后,adb client就可以向ADB servcer发送服务请求; 运行在pc端的adb server: ADB Server是运行在主机上的一个后台进程。它的作用在于检测USB端口感知设备的连接和拔除,以及模拟器实例的启动或停止,ADB Server还需要将adb client的请求通过usb或者tcp的方式发送到对应的adbd上; 运行在设备端的常驻进程adb demon (adbd): 程序“adbd”作为一个后台进程在Android设备或模拟器系统中运行。它的作用是连接ADB服务器,并且为运行在主机上的客户端提供一些服务。 adb下载及安装: 一共有两种方法: 首先第一种就是最简单的方法,只下载adb压缩包去解压即可:链接:https://pan.baidu.com/s/1SKu24yyShwg16lyIupO5VA 提取码:ih0i (备注:如果下载放入到D盘去解压,打开dos窗口那么就要进入到D盘,然后再去执行adb命令,输入adb查看它是否安装成功) 第二种方法前提是已安装了Android Studio,它本身带有adb命令,如果配置好的Android Studio 一般都是可以直接调用adb命令的;如果不行,找到adb在SDK里的绝对路径,放入环境变量path中(绝对路径不带入adb.exe) 然后输入adb version 查看版本 可以看出是否安装成功,如下就已经成功了。 启动 adb server 命令:adb start-server 停止 adb server 命令:adb kill-server 查询已连接设备/模拟器:adb devices 该命令经常出现以下问题: offline —— 表示设备未连接成功或无响应; device —— 设备已连接; no device —— 没有设备/模拟器连接; List of devices attached 设备/模拟器未连接到 adb 或无响应 USB连接: 在手机“设置”-“关于手机”连续点击“版本号”7 次,可以进入到开发者模式;然后可以到“设置”-“开发者选项”-“调试”里打开USB调试以及允许ADB的一些权限;连接时手机会弹出“允许HiSuite通过HDB连接设备”点击允许/接受即可; 驱动也是必须安装的,可以用豌豆荚,或者是手机商家提供的手机助手,点进去驱动器安装即可(部分电脑双击无法直接进入到驱动器里,可以使用右键找到进入点击即可) 再次输入adb devices验证是否连接成功,连接成功即如下图: 也可以进行无线连接,其中非root权限也需借助USB线进行操作,完成后即可断开USB线;root用户可以进行无线连接,具体步骤可以参考网上资源。 **查看是否有root权限:**输入adb shell,然后输入su KaTeX parse error: Expected 'EOF', got '#' at position 5: 如果变为#̲则成功,如果仍为则未有root权限;恢复命令:adb unroot 查看应用列表: 查看所有应用列表:adb shell pm list packages 查看系统应用列表:adb shell pm list packages -s 查看第三方应用列表:adb shell pm list packages -3: 安装apk:adb install “-lrtsdg” “path_to_apk” “-lrtsdg”: -l:将应用安装到保护目录 /mnt/asec; -r:允许覆盖安装; -t:允许安装 AndroidManifest.xml 里 application 指定 android:testOnly=“true” 的应用; -s:将应用安装到 sdcard; -d:允许降级覆盖安装; -g:授予所有运行时权限; path_to_apk:apk的绝对路径。 示例安装淘宝apk:adb install -l /data/local/tmp/taobao.apk 卸载apk:adb uninstall -k “packagename” “packagename”:表示应用的包名,以下相同; -k 参数可选,表示卸载应用但保留数据和缓存目录。 示例卸载 手机淘宝:adb uninstall com.taobao.taobao 清除应用数据与缓存命令:adb shell pm clear “packagename” 相当于在设置里的应用信息界面点击「清除缓存」和「清除数据」。 示例:adb shell pm clear com.taobao.taobao 表示清除 手机淘宝数据和缓存。 Android四大组件有Activity,Service服务,Content Provider内容提供,BroadcastReceiver广播接收器,具体不做多讲,常用的有以下: 查看前台 Activity命令:adb shell dumpsys activity activities | grep mFocusedActivity 查看正在运行的 Services命令:adb shell dumpsys activity services “packagename” 其中参数不是必须的,指定 “packagename” 表示查看与某个包名相关的 Services,不指定表示查看所有 Services。 查看应用详细信息命令:adb shell dumpsys package “packagename” 调起 Activity命令格式:adb shell am start [options] 例如:adb shell am start -n com.tencent.mm/.ui.LauncherUI表示调起微信主界面 调起 Service命令格式:adb shell am startservice [options] 例如:adb shell am startservice -n com.tencent.mm/.plugin.accountsync.model.AccountAuthenticatorService 表示调起微信的某 Service。 强制停止应用命令:adb shell am force-stop “packagename” 例如强制停止淘宝:adb shell am force-stop com.taobao.taobao 模拟按键/输入:adb shell input keyevent keycode 不同的 keycode有不同的功能: keycode 含义 3 HOME 键 4 返回键 5 打开拨号应用 6 挂断电话 26 电源键 27 拍照(需要在相机应用里) 61 Tab键 64 打开浏览器 67 退格键 80 拍照对焦键 82 菜单键 85 播放/暂停 86 停止播放 92 向上翻页键 93 向下翻页键 111 ESC键 112 删除键 122 移动光标到行首或列表顶部 123 移动光标到行末或列表底部 124 插入键 164 静音 176 打开系统设置 207 打开联系人 208 打开日历 209 打开音乐 220 降低屏幕亮度 221 提高屏幕亮度 223 系统休眠 224 点亮屏幕 224 点亮屏幕 224 点亮屏幕 231 打开语音助手 276 如果没有 wakelock 则让系统休眠 滑动解锁:如果锁屏没有密码,是通过滑动手势解锁,那么可以通过 input swipe 来解锁。 命令:adb shell input swipe 300 1000 300 500 (其中参数 300 1000 300 500 分别表示起始点x坐标 起始点y坐标 结束点x坐标 结束点y坐标。) 输入文本:在焦点处于某文本框时,可以通过 input 命令来输入文本。 命令:adb shell input text *** (***即为输入内容) 打印日志: Android 的日志分为如下几个优先级(priority): V —— Verbose(最低,输出得最多) D —— Debug I —— Info W —— Warning E —— Error F—— Fatal S —— Silent(最高,啥也不输出) 按某级别过滤日志则会将该级别及以上的日志输出。 比如,命令:adb logcat *:W 会将 Warning、Error、Fatal 和 Silent 日志输出。 (注: 在 macOS 下需要给 :W 这样以 作为 tag 的参数加双引号,如 adb logcat “:W”,不然会报错 no matches found: :W。) adb logcat 打印当前设备上所有日志 adb logcat :W 过滤打印严重级别W及以上的日志 adb logcat l findstr ***> F:\log.txt 把仅含的日志保存到F盘的log.txt文件中 adb logcat -c 清除屏幕上的日志记录 adb logcat -c && adb logcat -s ActivityManager l grep "Displayed” 客户端程序启动时间获取日志 adb logcat > F:\log.txt 打印当前设备上所有日志保存到F盘的log.txt文件中 adb logcat l findstr *** 打印过滤仅含的日志 adb logcat l findstr ***> F:\log.txt 把仅含**的日志保存到F盘的log.txt文件中 按 tag 和级别过滤日志:命令:adb logcat ActivityManager:I MyApp:D *:S 表示输出 tag ActivityManager 的 Info 以上级别日志,输出 tag MyApp 的 Debug 以上级别日志,及其它 tag 的 Silent 级别日志(即屏蔽其它 tag 日志)。 日志格式可以用:adb logcat -v 选项指定日志输出格式。 日志支持按以下几种 :默认格式brief、process、tag、raw、time、long 指定格式可与上面的过滤同时使用。比如:adb logcat -v long ActivityManager:I *:S 清空日志:adb logcat -c 内核日志:adb shell dmesg 查看设备情况: 查看设备信息型号命令:adb shell getprop ro.product.model 电池状况命令:adb shell dumpsys battery 屏幕分辨率命令:adb shell wm size 如果使用命令修改过,那输出可能是: Physical size: 1080x1920 Override size: 480x1024 表明设备的屏幕分辨率原本是 1080px * 1920px,当前被修改为 480px * 1024px。 屏幕密度命令:adb shell wm density 如果使用命令修改过,那输出可能是: Physical density: 480 Override density: 160 表明设备的屏幕密度原来是 480dpi,当前被修改为 160dpi。 显示屏参数:adb shell dumpsys window displays 输出示例: WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays) Display: mDisplayId=0 init=1080x1920 420dpi cur=1080x1920 app=1080x1794 rng=1080x1017-1810x1731 deferred=false layoutNeeded=false 其中 mDisplayId 为 显示屏编号,init 是初始分辨率和屏幕密度,app 的高度比 init 里的要小,表示屏幕底部有虚拟按键,高度为 1920 - 1794 = 126px 合 42dp。 android_id查看命令:adb shell settings get secure android_id 查看Android 系统版本:adb shell getprop ro.build.version.release 查看设备ip地址:adb shell ifconfig | grep Mask或者adb shell netcfg 查看CPU 信息命令:adb shell cat /proc/cpuinfo 查看内存信息命令:adb shell cat /proc/meminfo 更多硬件与系统属性: 设备的更多硬件与系统属性可以通过如下命令查看:adb shell cat /system/build.prop 单独查看某一硬件或系统属性:adb shell getprop <属性名> 属性名 含义 ro.build.version.sdk SDK 版本 ro.build.version.release Android 系统版本 ro.product.model 型号 ro.product.brand 品牌 ro.product.name 设备名 ro.product.board 处理器型号 persist.sys.isUsbOtgEnabled 是否支持 OTG dalvik.vm.heapsize 每个应用程序的内存上限 ro.sf.lcd_density 屏幕密度 rro.build.version.security_patch Android 安全补丁程序级别 修改设置: 修改设置之后,运行恢复命令有可能显示仍然不太正常,可以运行 adb reboot 重启设备,或手动重启。 修改设置的原理主要是通过 settings 命令修改 /data/data/com.android.providers.settings/databases/settings.db 里存放的设置值。 修改分辨率命令:adb shell wm size 480x1024 恢复原分辨率命令:adb shell wm size reset 修改屏幕密度命令:adb shell wm density 160 表示将屏幕密度修改为 160dpi;恢复原屏幕密度命令:adb shell wm density reset 修改显示区域命令:adb shell wm overscan 0,0,0,200 四个数字分别表示距离左、上、右、下边缘的留白像素,以上命令表示将屏幕底部 200px 留白。恢复原显示区域命令:adb shell wm overscan reset 关闭 USB 调试模式命令:adb shell settings put global adb_enabled 0 需要手动恢复:「设置」-「开发者选项」-「Android 调试」 状态栏和导航栏的显示隐藏:adb shell settings put global policy_control 可由如下几种键及其对应的值组成,格式为 =:=。 key 含义 immersive.full 同时隐藏 immersive.status 隐藏状态栏 immersive.navigation 隐藏导航栏 immersive.preconfirms ? 这些键对应的值可则如下值用逗号组合: value 含义 apps 所有应用 * 所有界面 packagename 指定应用 -packagename 排除指定应用 举例:adb shell settings put global policy_control immersive.full=* 表示设置在所有界面下都同时隐藏状态栏和导航栏。 举例:adb shell settings put global policy_control immersive.status=com.package1,com.package2:immersive.navigation=apps,-com.package3 表示设置在包名为 com.package1 和 com.package2 的应用里隐藏状态栏,在除了包名为 com.package3 的所有应用里隐藏导航栏。 恢复正常模式:adb shell settings put global policy_control null 实用功能: 截图保存到电脑:adb exec-out screencap -p > sc.png 然后将 png 文件导出到电脑:adb pull /sdcard/sc.png 录制屏幕:录制屏幕以 mp4 格式保存到 /sdcard:adb shell screenrecord /sdcard/filename.mp4 需要停止时按 Ctrl-C,默认录制时间和最长录制时间都是 180 秒。 如果需要导出到电脑:adb pull /sdcard/filename.mp4 挂载、查看连接过的 WiFi 密码、开启/关闭 WiFi、设置系统日期和时间都需要root权限,不做多说。 使用 Monkey 进行压力测试:Monkey 可以生成伪随机用户事件来模拟单击、触摸、手势等操作,可以对正在开发中的程序进行随机压力测试。 简单用法:adb shell monkey -p < packagename > -v 500 表示向 指定的应用程序发送 500 个伪随机事件。 查看进程:adb shell ps 查看实时资源占用情况:adb shell top 查看进程 UID:adb shell dumpsys package | grep userId=
问问小秘 2020-04-29 15:55:55 0 浏览量 回答数 0

回答

134题 其实就是水平扩容了,Zookeeper在这方面不太好。两种方式:全部重启:关闭所有Zookeeper服务,修改配置之后启动。不影响之前客户端的会话。逐个重启:这是比较常用的方式。 133题 集群最低3(2N+1)台,保证奇数,主要是为了选举算法。一个由 3 台机器构成的 ZooKeeper 集群,能够在挂掉 1 台机器后依然正常工作,而对于一个由 5 台服务器构成的 ZooKeeper 集群,能够对 2 台机器挂掉的情况进行容灾。注意,如果是一个由6台服务器构成的 ZooKeeper 集群,同样只能够挂掉 2 台机器,因为如果挂掉 3 台,剩下的机器就无法实现过半了。 132题 基于“过半”设计原则,ZooKeeper 在运行期间,集群中至少有过半的机器保存了最新的数据。因此,只要集群中超过半数的机器还能够正常工作,整个集群就能够对外提供服务。 131题 不是。官方声明:一个Watch事件是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端,以便通知它们。为什么不是永久的,举个例子,如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,这太消耗性能了。一般是客户端执行getData(“/节点A”,true),如果节点A发生了变更或删除,客户端会得到它的watch事件,但是在之后节点A又发生了变更,而客户端又没有设置watch事件,就不再给客户端发送。在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我只要最新的数据即可。 130题 数据发布/订阅,负载均衡,命名服务,分布式协调/通知,集群管理,Master 选举,分布式锁,分布式队列 129题 客户端 SendThread 线程接收事件通知, 交由 EventThread 线程回调 Watcher。客户端的 Watcher 机制同样是一次性的, 一旦被触发后, 该 Watcher 就失效了。 128题 1、服务端接收 Watcher 并存储; 2、Watcher 触发; 2.1 封装 WatchedEvent; 2.2 查询 Watcher; 2.3 没找到;说明没有客户端在该数据节点上注册过 Watcher; 2.4 找到;提取并从 WatchTable 和 Watch2Paths 中删除对应 Watcher; 3、调用 process 方法来触发 Watcher。 127题 1.调用 getData()/getChildren()/exist()三个 API,传入 Watcher 对象 2.标记请求 request,封装 Watcher 到 WatchRegistration 3.封装成 Packet 对象,发服务端发送 request 4.收到服务端响应后,将 Watcher 注册到 ZKWatcherManager 中进行管理 5.请求返回,完成注册。 126题 Zookeeper 允许客户端向服务端的某个 Znode 注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。工作机制:(1)客户端注册 watcher(2)服务端处理 watcher(3)客户端回调 watcher 125题 服务器具有四种状态,分别是 LOOKING、FOLLOWING、LEADING、OBSERVING。 LOOKING:寻 找 Leader 状态。当服务器处于该状态时,它会认为当前集群中没有 Leader,因此需要进入 Leader 选举状态。 FOLLOWING:跟随者状态。表明当前服务器角色是 Follower。 LEADING:领导者状态。表明当前服务器角色是 Leader。 OBSERVING:观察者状态。表明当前服务器角色是 Observer。 124题 Zookeeper 有三种部署模式:单机部署:一台集群上运行;集群部署:多台集群运行;伪集群部署:一台集群启动多个 Zookeeper 实例运行。 123题 Paxos算法是分布式选举算法,Zookeeper使用的 ZAB协议(Zookeeper原子广播),二者有相同的地方,比如都有一个Leader,用来协调N个Follower的运行;Leader要等待超半数的Follower做出正确反馈之后才进行提案;二者都有一个值来代表Leader的周期。不同的地方在于:ZAB用来构建高可用的分布式数据主备系统(Zookeeper),Paxos是用来构建分布式一致性状态机系统。Paxos算法、ZAB协议要想讲清楚可不是一时半会的事儿,自1990年莱斯利·兰伯特提出Paxos算法以来,因为晦涩难懂并没有受到重视。后续几年,兰伯特通过好几篇论文对其进行更进一步地解释,也直到06年谷歌发表了三篇论文,选择Paxos作为chubby cell的一致性算法,Paxos才真正流行起来。对于普通开发者来说,尤其是学习使用Zookeeper的开发者明确一点就好:分布式Zookeeper选举Leader服务器的算法与Paxos有很深的关系。 122题 ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议(paxos算法的一种实现)。ZAB协议包括两种基本的模式:崩溃恢复和消息广播。当整个zookeeper集群刚刚启动或者Leader服务器宕机、重启或者网络故障导致不存在过半的服务器与Leader服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的Leader服务器,然后集群中Follower服务器开始与新的Leader服务器进行数据同步,当集群中超过半数机器与该Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式,Leader服务器开始接收客户端的事务请求生成事物提案来进行事务请求处理。 121题 Zookeeper本身也是集群,推荐配置不少于3个服务器。Zookeeper自身也要保证当一个节点宕机时,其他节点会继续提供服务。如果是一个Follower宕机,还有2台服务器提供访问,因为Zookeeper上的数据是有多个副本的,数据并不会丢失;如果是一个Leader宕机,Zookeeper会选举出新的Leader。ZK集群的机制是只要超过半数的节点正常,集群就能正常提供服务。只有在ZK节点挂得太多,只剩一半或不到一半节点能工作,集群才失效。所以,3个节点的cluster可以挂掉1个节点(leader可以得到2票>1.5),2个节点的cluster就不能挂掉任何1个节点了(leader可以得到1票<=1)。 120题 选完Leader以后,zk就进入状态同步过程。1、Leader等待server连接;2、Follower连接leader,将最大的zxid发送给leader;3、Leader根据follower的zxid确定同步点;4、完成同步后通知follower 已经成为uptodate状态;5、Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。 119题 在zookeeper集群中也是一样,每个节点都会投票,如果某个节点获得超过半数以上的节点的投票,则该节点就是leader节点了。zookeeper中有三种选举算法,分别是LeaderElection,FastLeaderElection,AuthLeaderElection, FastLeaderElection此算法和LeaderElection不同的是它不会像后者那样在每轮投票中要搜集到所有结果后才统计投票结果,而是不断的统计结果,一旦没有新的影响leader结果的notification出现就返回投票结果。这样的效率更高。 118题 zk的负载均衡是可以调控,nginx只是能调权重,其他需要可控的都需要自己写插件;但是nginx的吞吐量比zk大很多,应该说按业务选择用哪种方式。 117题 Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。 116题 有临时节点和永久节点,分再细一点有临时有序/无序节点,有永久有序/无序节点。当创建临时节点的程序结束后,临时节点会自动消失,临时节点上的数据也会一起消失。 115题 在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,这就是主节点存在的意义。 114题 ZooKeeper 实现分布式事务,类似于两阶段提交,总共分为以下 4 步:客户端先给 ZooKeeper 节点发送写请求;ZooKeeper 节点将写请求转发给 Leader 节点,Leader 广播给集群要求投票,等待确认;Leader 收到确认,统计投票,票数过半则提交事务;事务提交成功后,ZooKeeper 节点告知客户端。 113题 ZooKeeper 实现分布式锁的步骤如下:客户端连接 ZooKeeper,并在 /lock 下创建临时的且有序的子节点,第一个客户端对应的子节点为 /lock/lock-10000000001,第二个为 /lock/lock-10000000002,以此类推。客户端获取 /lock 下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听刚好在自己之前一位的子节点删除消息,获得子节点变更通知后重复此步骤直至获得锁;执行业务代码;完成业务流程后,删除对应的子节点释放锁。 112题 ZooKeeper 特性如下:顺序一致性(Sequential Consistency):来自相同客户端提交的事务,ZooKeeper 将严格按照其提交顺序依次执行;原子性(Atomicity):于 ZooKeeper 集群中提交事务,事务将“全部完成”或“全部未完成”,不存在“部分完成”;单一系统镜像(Single System Image):客户端连接到 ZooKeeper 集群的任意节点,其获得的数据视图都是相同的;可靠性(Reliability):事务一旦完成,其产生的状态变化将永久保留,直到其他事务进行覆盖;实时性(Timeliness):事务一旦完成,客户端将于限定的时间段内,获得最新的数据。 111题 ZooKeeper 通常有三种搭建模式:单机模式:zoo.cfg 中只配置一个 server.id 就是单机模式了,此模式一般用在测试环境,如果当前主机宕机,那么所有依赖于当前 ZooKeeper 服务工作的其他服务器都不能进行正常工作;伪分布式模式:在一台机器启动不同端口的 ZooKeeper,配置到 zoo.cfg 中,和单机模式相同,此模式一般用在测试环境;分布式模式:多台机器各自配置 zoo.cfg 文件,将各自互相加入服务器列表,上面搭建的集群就是这种完全分布式。 110题 ZooKeeper 主要提供以下功能:分布式服务注册与订阅:在分布式环境中,为了保证高可用性,通常同一个应用或同一个服务的提供方都会部署多份,达到对等服务。而消费者就须要在这些对等的服务器中选择一个来执行相关的业务逻辑,比较典型的服务注册与订阅,如 Dubbo。分布式配置中心:发布与订阅模型,即所谓的配置中心,顾名思义就是发布者将数据发布到 ZooKeeper 节点上,供订阅者获取数据,实现配置信息的集中式管理和动态更新。命名服务:在分布式系统中,通过命名服务客户端应用能够根据指定名字来获取资源、服务地址和提供者等信息。分布式锁:这个主要得益于 ZooKeeper 为我们保证了数据的强一致性。 109题 Dubbo是 SOA 时代的产物,它的关注点主要在于服务的调用,流量分发、流量监控和熔断。而 Spring Cloud诞生于微服务架构时代,考虑的是微服务治理的方方面面,另外由于依托了 Spirng、Spirng Boot的优势之上,两个框架在开始目标就不一致,Dubbo 定位服务治理、Spirng Cloud 是一个生态。 108题 Dubbo通过Token令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。Dubbo还提供服务黑白名单,来控制服务所允许的调用方。 107题 Dubbo超时时间设置有两种方式: 服务提供者端设置超时时间,在Dubbo的用户文档中,推荐如果能在服务端多配置就尽量多配置,因为服务提供者比消费者更清楚自己提供的服务特性。 服务消费者端设置超时时间,如果在消费者端设置了超时时间,以消费者端为主,即优先级更高。因为服务调用方设置超时时间控制性更灵活。如果消费方超时,服务端线程不会定制,会产生警告。 106题 Random LoadBalance: 随机选取提供者策略,有利于动态调整提供者权重。截面碰撞率高,调用次数越多,分布越均匀; RoundRobin LoadBalance: 轮循选取提供者策略,平均分布,但是存在请求累积的问题; LeastActive LoadBalance: 最少活跃调用策略,解决慢提供者接收更少的请求; ConstantHash LoadBalance: 一致性Hash策略,使相同参数请求总是发到同一提供者,一台机器宕机,可以基于虚拟节点,分摊至其他提供者,避免引起提供者的剧烈变动; 缺省时为Random随机调用。 105题 Consumer(消费者),连接注册中心 ,并发送应用信息、所求服务信息至注册中心。 注册中心根据 消费 者所求服务信息匹配对应的提供者列表发送至Consumer 应用缓存。 Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用。 Provider 状态变更会实时通知注册中心、在由注册中心实时推送至Consumer。 104题 Provider:暴露服务的服务提供方。 Consumer:调用远程服务的服务消费方。 Registry:服务注册与发现的注册中心。 Monitor:统计服务的调用次调和调用时间的监控中心。 Container:服务运行容器。 103题 主要就是如下3个核心功能: Remoting:网络通信框架,提供对多种NIO框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式。 Cluster:服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。 Registry:服务注册,基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。 102题 透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。 101题 垂直分表定义:将一个表按照字段分成多表,每个表存储其中一部分字段。水平分表是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中。 100题 垂直分库是指按照业务将表进行分类,分布到不同的数据库上面,每个库可以放在不同的服务器上,它的核心理念是专库专用。水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。 99题 QPS:每秒查询数。TPS:每秒处理事务数。Uptime:服务器已经运行的时间,单位秒。Questions:已经发送给数据库查询数。Com_select:查询次数,实际操作数据库的。Com_insert:插入次数。Com_delete:删除次数。Com_update:更新次数。Com_commit:事务次数。Com_rollback:回滚次数。 98题 如果需要跨主机进行JOIN,跨应用进行JOIN,或者数据库不能获得较好的执行计划,都可以自己通过程序来实现JOIN。 例如:SELECT a.,b. FROM a,b WHERE a.col1=b.col1 AND a.col2> 10 ORDER BY a.col2; 可以利用程序实现,先SELECT * FROM a WHERE a.col2>10 ORDER BY a.col2;–(1) 利用(1)的结果集,做循环,SELECT * FROM b WHERE b.col1=a.col1; 这样可以避免排序,可以在程序里控制执行的速度,有效降低数据库压力,也可以实现跨主机的JOIN。 97题 搭建复制的必备条件:复制的机器之间网络通畅,Master打开了binlog。 搭建复制步骤:建立用户并设置权限,修改配置文件,查看master状态,配置slave,启动从服务,查看slave状态,主从测试。 96题 Heartbeat方案:利用Heartbeat管理VIP,利用crm管理MySQL,MySQL进行双M复制。(Linux系统下没有分库的标准方案)。 LVS+Keepalived方案:利用Keepalived管理LVS和VIP,LVS分发请求到MySQL,MySQL进行双M复制。(Linux系统下无分库无事务的方案)。 Cobar方案:利用Cobar进行HA和分库,应用程序请求Cobar,Cobar转发请求道数据库。(有分库的标准方案,Unix下唯一方案)。 95题 聚集(clustered)索引,也叫聚簇索引,数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。但是,覆盖索引可以模拟多个聚集索引。存储引擎负责实现索引,因此不是所有的存储索引都支持聚集索引。当前,SolidDB和InnoDB是唯一支持聚集索引的存储引擎。 优点:可以把相关数据保存在一起。数据访问快。 缺点:聚集能最大限度地提升I/O密集负载的性能。聚集能最大限度地提升I/O密集负载的性能。建立在聚集索引上的表在插入新行,或者在行的主键被更新,该行必须被移动的时候会进行分页。聚集表可会比全表扫描慢,尤其在表存储得比较稀疏或因为分页而没有顺序存储的时候。第二(非聚集)索引可能会比预想的大,因为它们的叶子节点包含了被引用行的主键列。 94题 以下原因是导致mysql 表毁坏的常见原因: 服务器突然断电导致数据文件损坏; 强制关机,没有先关闭mysql 服务; mysqld 进程在写表时被杀掉; 使用myisamchk 的同时,mysqld 也在操作表; 磁盘故障;服务器死机;mysql 本身的bug 。 93题 1.定位慢查询 首先先打开慢查询日志设置慢查询时间; 2.分析慢查询(使用explain工具分析sql语句); 3.优化慢查询 。
游客ih62co2qqq5ww 2020-06-15 13:55:41 0 浏览量 回答数 0

问题

PCI远程扫描漏洞补丁如何解决

您好:求助一下,一下问题如何解决 2018-08-07   Scan ID 8238876 Max CVSS 10.0 Scan State Completed Scan Compliance Status F...
1298117508539047 2019-12-01 18:51:40 2296 浏览量 回答数 0

回答

1 写出下面代码输出内容。 package main import (    "fmt" ) funcmain() {     defer_call() } funcdefer_call() {     deferfunc() {fmt.Println("打印前")}()     deferfunc() {fmt.Println("打印中")}()     deferfunc() {fmt.Println("打印后")}()     panic("触发异常") } 考点:defer执行顺序 解答: defer 是后进先出。 panic 需要等defer 结束后才会向上传递。 出现panic恐慌时候,会先按照defer的后入先出的顺序执行,最后才会执行panic。 打印后 打印中 打印前 panic: 触发异常 2 以下代码有什么问题,说明原因。 type student struct {     Name string     Age  int } funcpase_student() {     m := make(map[string]*student)     stus := []student{         {Name: "zhou",Age: 24},         {Name: "li",Age: 23},         {Name: "wang",Age: 22},     }    for _,stu := range stus {         m[stu.Name] =&stu     } } 考点:foreach 解答: 这样的写法初学者经常会遇到的,很危险! 与Java的foreach一样,都是使用副本的方式。所以m[stu.Name]=&stu实际上一致指向同一个指针, 最终该指针的值为遍历的最后一个struct的值拷贝。 就像想修改切片元素的属性: for _, stu := rangestus {     stu.Age = stu.Age+10} 也是不可行的。 大家可以试试打印出来: func pase_student() {     m := make(map[string]*student)     stus := []student{         {Name: "zhou",Age: 24},         {Name: "li",Age: 23},         {Name: "wang",Age: 22},     }         // 错误写法     for _,stu := range stus {         m[stu.Name] =&stu     }          fork,v:=range m{               println(k,"=>",v.Name)     }           // 正确     for i:=0;i<len(stus);i++ {        m[stus[i].Name] = &stus[i]     }          fork,v:=range m{                println(k,"=>",v.Name)     } } 3 下面的代码会输出什么,并说明原因 func main() {     runtime.GOMAXPROCS(1)     wg := sync.WaitGroup{}     wg.Add(20)   for i := 0; i < 10; i++ {                  gofunc() {            fmt.Println("A: ", i)            wg.Done()         }()     }             for i:= 0; i < 10; i++ {                    gofunc(i int) {            fmt.Println("B: ", i)            wg.Done()         }(i)     }     wg.Wait() } 考点:go执行的随机性和闭包 解答: 谁也不知道执行后打印的顺序是什么样的,所以只能说是随机数字。 但是A:均为输出10,B:从0~9输出(顺序不定)。 第一个go func中i是外部for的一个变量,地址不变化。遍历完成后,最终i=10。 故go func执行时,i的值始终是10。 第二个go func中i是函数参数,与外部for中的i完全是两个变量。 尾部(i)将发生值拷贝,go func内部指向值拷贝地址。 4 下面代码会输出什么? type People struct{}func (p People)ShowA() {     fmt.Println("showA")     p.ShowB() } func(pPeople)ShowB() {     fmt.Println("showB") } typeTeacher struct {     People } func(t*Teacher)ShowB() {     fmt.Println("teachershowB") } funcmain() {     t := Teacher{}     t.ShowA() } 考点:go的组合继承 解答: 这是Golang的组合模式,可以实现OOP的继承。 被组合的类型People所包含的方法虽然升级成了外部类型Teacher这个组合类型的方法(一定要是匿名字段),但它们的方法(ShowA())调用时接受者并没有发生变化。 此时People类型并不知道自己会被什么类型组合,当然也就无法调用方法时去使用未知的组合者Teacher类型的功能。 showAshowB 5 下面代码会触发异常吗?请详细说明 func main() {     runtime.GOMAXPROCS(1)     int_chan := make(chanint, 1)     string_chan := make(chanstring, 1)     int_chan <- 1     string_chan <- "hello"     select {                case value := <-int_chan:        fmt.Println(value)           casevalue := <-string_chan:                   panic(value)     } } 考点:select随机性 解答: select会随机选择一个可用通用做收发操作。 所以代码是有肯触发异常,也有可能不会。 单个chan如果无缓冲时,将会阻塞。但结合 select可以在多个chan间等待执行。有三点原则: select 中只要有一个case能return,则立刻执行。 当如果同一时间有多个case均能return则伪随机方式抽取任意一个执行。 如果没有一个case能return则可以执行”default”块。 6 下面代码输出什么? funccalc(indexstring, a, bint) int {     ret := a+ b     fmt.Println(index,a, b, ret)     return ret } funcmain() {          a := 1     b := 2     defer calc("1", a,calc("10", a, b))    a = 0     defer calc("2", a,calc("20", a, b))    b = 1 } 考点:defer执行顺序 解答: 这道题类似第1题 需要注意到defer执行顺序和值传递 index:1肯定是最后执行的,但是index:1的第三个参数是一个函数,所以最先被调用 calc("10",1,2)==>10,1,2,3 执行index:2时,与之前一样,需要先调用calc("20",0,2)==>20,0,2,2 执行到b=1时候开始调用,index:2==>calc("2",0,2)==>2,0,2,2最后执行index:1==>calc("1",1,3)==>1,1,3,4 10 1 2 320 0 2 22 0 2 21 1 3 4 7 请写出以下输入内容 funcmain() {            s := make([]int,5)     s = append(s,1, 2, 3)     fmt.Println(s) } 考点:make默认值和append 解答: make初始化是由默认值的哦,此处默认值为0 [00000123] 大家试试改为: s := make([]int, 0) s = append(s, 1, 2, 3) fmt.Println(s)//[1 2 3] 8 下面的代码有什么问题? type UserAges struct {     ages map[string]int     sync.Mutex } func(uaUserAges)Add(name string, age int) {     ua.Lock()          deferua.Unlock()     ua.ages[name] = age } func(uaUserAges)Get(name string)int {           ifage, ok := ua.ages[name]; ok {                  return age     }         return-1 } 考点:map线程安全 解答: 可能会出现 fatal error: concurrent mapreadandmapwrite. 修改一下看看效果 func (ua *UserAges)Get(namestring)int {     ua.Lock()          deferua.Unlock()          ifage, ok := ua.ages[name]; ok {                   return age     }            return-1 } 9.   下面的迭代会有什么问题? func (set *threadSafeSet)Iter()<-chaninterface{} {     ch := make(chaninterface{})                  gofunc() {         set.RLock()                for elem := range set.s {            ch <- elem         }                   close(ch)         set.RUnlock()     }()      return ch } 考点:chan缓存池 解答: 看到这道题,我也在猜想出题者的意图在哪里。 chan?sync.RWMutex?go?chan缓存池?迭代? 所以只能再读一次题目,就从迭代入手看看。 既然是迭代就会要求set.s全部可以遍历一次。但是chan是为缓存的,那就代表这写入一次就会阻塞。 我们把代码恢复为可以运行的方式,看看效果 package main import (          "sync"     "fmt")//下面的迭代会有什么问题?type threadSafeSet struct {     sync.RWMutex     s []interface{} } func(set*threadSafeSet)Iter() <-chaninterface{} {     //ch := make(chan interface{}) // 解除注释看看!     ch := make(chaninterface{},len(set.s))    gofunc() {         set.RLock()        forelem,value := range set.s {            ch <- elem             println("Iter:",elem,value)         }       close(ch)         set.RUnlock()     }()     return ch } funcmain() {     th:=threadSafeSet{         s:[]interface{}{"1","2"},     }     v:=<-th.Iter()     fmt.Sprintf("%s%v","ch",v) } 10 以下代码能编译过去吗?为什么? package main import (   "fmt") typePeople interface {     Speak(string) string } typeStduent struct{} func(stu*Stduent)Speak(think string)(talk string) {     ifthink == "bitch" {         talk = "Youare a good boy"     } else {         talk = "hi"     }     return } funcmain() {     var peoPeople = Stduent{}     think := "bitch"    fmt.Println(peo.Speak(think)) } 考点:golang的方法集 解答: 编译不通过! 做错了!?说明你对golang的方法集还有一些疑问。 一句话:golang的方法集仅仅影响接口实现和方法表达式转化,与通过实例或者指针调用方法无关。 11 以下代码打印出来什么内容,说出为什么。 package main import (   "fmt") typePeople interface {     Show() } typeStudent struct{} func(stuStudent)Show() { } funclive()People {     var stuStudent     return stu } funcmain() {   if live() == nil {         fmt.Println("AAAAAAA")     } else {         fmt.Println("BBBBBBB")     } } 考点:interface内部结构 解答: 很经典的题! 这个考点是很多人忽略的interface内部结构。 go中的接口分为两种一种是空的接口类似这样: varininterface{} 另一种如题目: type People interface {     Show() } 他们的底层结构如下: type eface struct {      //空接口     _type _type        //类型信息     data  unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void)} typeiface struct {      //带有方法的接口     tab  itab          //存储type信息还有结构实现方法的集合     data unsafe.Pointer  //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void)} type_type struct {     size       uintptr //类型大小     ptrdata    uintptr //前缀持有所有指针的内存大小     hash       uint32  //数据hash值     tflag     tflag     align      uint8   //对齐     fieldalign uint8   //嵌入结构体时的对齐     kind       uint8   //kind 有些枚举值kind等于0是无效的     alg       *typeAlg //函数指针数组,类型实现的所有方法     gcdata    *byte   str       nameOff     ptrToThis typeOff }type itab struct {     inter  *interfacetype //接口类型     _type  *_type         //结构类型     link   *itab     bad    int32     inhash int32     fun    [1]uintptr     //可变大小方法集合} 可以看出iface比eface 中间多了一层itab结构。 itab 存储_type信息和[]fun方法集,从上面的结构我们就可得出,因为data指向了nil 并不代表interface 是nil, 所以返回值并不为空,这里的fun(方法集)定义了接口的接收规则,在编译的过程中需要验证是否实现接口 结果: BBBBBBB 12.是否可以编译通过?如果通过,输出什么? func main() {     i := GetValue() switch i.(type) {          caseint:                println("int")            casestring:                println("string")            caseinterface{}:                println("interface")            default:                 println("unknown")     } } funcGetValue()int {    return1 } 解析 考点:type 编译失败,因为type只能使用在interface 13.下面函数有什么问题? func funcMui(x,y int)(sum int,error){     returnx+y,nil } 解析 考点:函数返回值命名 在函数有多个返回值时,只要有一个返回值有指定命名,其他的也必须有命名。 如果返回值有有多个返回值必须加上括号; 如果只有一个返回值并且有命名也需要加上括号; 此处函数第一个返回值有sum名称,第二个未命名,所以错误。 14.是否可以编译通过?如果通过,输出什么? package mainfunc main() {    println(DeferFunc1(1)) println(DeferFunc2(1)) println(DeferFunc3(1)) }func DeferFunc1(i int)(t int) {     t = i   deferfunc() {         t += 3     }() return t } funcDeferFunc2(i int)int {     t := i  deferfunc() {         t += 3     }() return t } funcDeferFunc3(i int)(t int) {   deferfunc() {         t += i     }() return2} 解析 考点:defer和函数返回值 需要明确一点是defer需要在函数结束前执行。 函数返回值名字会在函数起始处被初始化为对应类型的零值并且作用域为整个函数 DeferFunc1有函数返回值t作用域为整个函数,在return之前defer会被执行,所以t会被修改,返回4; DeferFunc2函数中t的作用域为函数,返回1;DeferFunc3返回3 15.是否可以编译通过?如果通过,输出什么? funcmain() {    list := new([]int)     list = append(list,1)     fmt.Println(list) } 解析 考点:new list:=make([]int,0) 16.是否可以编译通过?如果通过,输出什么? package mainimport "fmt"funcmain() {     s1 := []int{1, 2, 3}     s2 := []int{4, 5}     s1 = append(s1,s2)     fmt.Println(s1) } 解析 考点:append append切片时候别漏了'…' 17.是否可以编译通过?如果通过,输出什么? func main() {     sn1 := struct {         age  int         name string     }{age: 11,name: "qq"}     sn2 := struct {         age  int         name string     }{age: 11,name: "qq"}  if sn1== sn2 {         fmt.Println("sn1== sn2")     }     sm1 := struct {         age int         m   map[string]string     }{age: 11, m:map[string]string{"a": "1"}}     sm2 := struct {         age int         m   map[string]string     }{age: 11, m:map[string]string{"a": "1"}}             if sm1 == sm2 {         fmt.Println("sm1== sm2")     } } 解析 考点:结构体比较 进行结构体比较时候,只有相同类型的结构体才可以比较,结构体是否相同不但与属性类型个数有关,还与属性顺序相关。 sn3:= struct {     name string     age  int } {age:11,name:"qq"} sn3与sn1就不是相同的结构体了,不能比较。 还有一点需要注意的是结构体是相同的,但是结构体属性中有不可以比较的类型,如map,slice。 如果该结构属性都是可以比较的,那么就可以使用“==”进行比较操作。 可以使用reflect.DeepEqual进行比较 if reflect.DeepEqual(sn1, sm) {     fmt.Println("sn1==sm") }else {     fmt.Println("sn1!=sm") } 所以编译不通过: invalid operation: sm1 == sm2 18.是否可以编译通过?如果通过,输出什么? func Foo(x interface{}) {    if x== nil {         fmt.Println("emptyinterface")                 return     }     fmt.Println("non-emptyinterface") }        funcmain() {           var x *int = nil     Foo(x) } 解析 考点:interface内部结构 non-emptyinterface 19.是否可以编译通过?如果通过,输出什么? func GetValue(m map[int]string, id int)(string, bool) {              if _,exist := m[id]; exist {                    return"存在数据", true     }            returnnil, false}funcmain() {     intmap:=map[int]string{    1:"a",        2:"bb",        3:"ccc",     }     v,err:=GetValue(intmap,3)     fmt.Println(v,err) } 解析 考点:函数返回值类型 nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。但是如果不特别指定的话,Go 语言不能识别类型,所以会报错。报:cannot use nil as type string in return argument. 20.是否可以编译通过?如果通过,输出什么? const (     x = iota     y     z = "zz"     k     p = iota) funcmain()  {     fmt.Println(x,y,z,k,p) } 解析 考点:iota 结果: 0 1 zz zz 4 21.编译执行下面代码会出现什么? package mainvar(     size :=1024     max_size = size*2) funcmain() {     println(size,max_size) } 解析 考点:变量简短模式 变量简短模式限制: 定义变量同时显式初始化 不能提供数据类型 只能在函数内部使用 结果: syntaxerror: unexpected := 22.下面函数有什么问题? package main const cl = 100 var bl   = 123 funcmain() {     println(&bl,bl)    println(&cl,cl) } 解析 考点:常量 常量不同于变量的在运行期分配内存,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用, cannot take the address of cl 23.编译执行下面代码会出现什么? package main funcmain() {     for i:=0;i<10;i++  {     loop:        println(i)     }    gotoloop } 解析 考点:goto goto不能跳转到其他函数或者内层代码 goto loop jumps intoblock starting at 24.编译执行下面代码会出现什么? package main import"fmt" funcmain() {      typeMyInt1 int      typeMyInt2 = int     var i int =9     var i1MyInt1 = i     var i2MyInt2 = i     fmt.Println(i1,i2) } 解析 考点:**Go 1.9 新特性 Type Alias ** 基于一个类型创建一个新类型,称之为defintion;基于一个类型创建一个别名,称之为alias。 MyInt1为称之为defintion,虽然底层类型为int类型,但是不能直接赋值,需要强转; MyInt2称之为alias,可以直接赋值。 结果: cannot use i (typeint) astype MyInt1 in assignment 25.编译执行下面代码会出现什么? package main import"fmt" typeUser struct { } typeMyUser1 User typeMyUser2 = User func(iMyUser1)m1(){     fmt.Println("MyUser1.m1") } func(iUser)m2(){     fmt.Println("User.m2") } funcmain() {     var i1MyUser1     var i2MyUser2     i1.m1()     i2.m2() } 解析 考点:**Go 1.9 新特性 Type Alias ** 因为MyUser2完全等价于User,所以具有其所有的方法,并且其中一个新增了方法,另外一个也会有。 但是 i1.m2() 是不能执行的,因为MyUser1没有定义该方法。 结果: MyUser1.m1User.m2 26.编译执行下面代码会出现什么? package main import"fmt" type T1 struct { } func(tT1)m1(){     fmt.Println("T1.m1") } type T2= T1 typeMyStruct struct {     T1     T2 } funcmain() {     my:=MyStruct{}     my.m1() } 解析 考点:**Go 1.9 新特性 Type Alias ** 是不能正常编译的,异常: ambiguousselectormy.m1 结果不限于方法,字段也也一样;也不限于type alias,type defintion也是一样的,只要有重复的方法、字段,就会有这种提示,因为不知道该选择哪个。 改为: my.T1.m1() my.T2.m1() type alias的定义,本质上是一样的类型,只是起了一个别名,源类型怎么用,别名类型也怎么用,保留源类型的所有方法、字段等。 27.编译执行下面代码会出现什么? package main import (           "errors"     "fmt") varErrDidNotWork = errors.New("did not work") funcDoTheThing(reallyDoItbool)(errerror) {     ifreallyDoIt {         result, err:= tryTheThing()         if err!= nil || result != "it worked" {            err = ErrDidNotWork         }     }    return err } functryTheThing()(string,error) {     return"",ErrDidNotWork } funcmain() {     fmt.Println(DoTheThing(true))     fmt.Println(DoTheThing(false)) } 解析 考点:变量作用域 因为 if 语句块内的 err 变量会遮罩函数作用域内的 err 变量,结果: 改为: func DoTheThing(reallyDoIt bool)(errerror) {     varresult string     ifreallyDoIt {         result, err =tryTheThing()         if err!= nil || result != "it worked" {            err = ErrDidNotWork         }     }    return err } 28.编译执行下面代码会出现什么? package main functest() []func() {     varfuns []func()     fori:=0;i<2;i++  {         funs = append(funs,func() {                       println(&i,i)         })     }    returnfuns } funcmain(){     funs:=test()            for_,f:=range funs{         f()     } } 解析 考点:闭包延迟求值 for循环复用局部变量i,每一次放入匿名函数的应用都是想一个变量。 结果: 0xc042046000 2 0xc042046000 2 如果想不一样可以改为: func test() []func()  {     varfuns []func()     fori:=0;i<2;i++  {         x:=i         funs = append(funs,func() {            println(&x,x)         })     }    returnfuns } 29.编译执行下面代码会出现什么? package main functest(x int)(func(),func()) {     returnfunc() {        println(x)     x+=10     }, func() {              println(x)     } } funcmain() {     a,b:=test(100)     a()     b() } 解析 考点:闭包引用相同变量* 结果: 100 110 30. 编译执行下面代码会出现什么? package main im port (   "fmt"     "reflect") funcmain1() {     deferfunc() {      iferr:=recover();err!=nil{           fmt.Println(err)        }else {           fmt.Println("fatal")        }     }()     deferfunc() {        panic("deferpanic")     }()     panic("panic") } funcmain() {     deferfunc() {        iferr:=recover();err!=nil{            fmt.Println("++++")            f:=err.(func()string)             fmt.Println(err,f(),reflect.TypeOf(err).Kind().String())         }else {            fmt.Println("fatal")         }     }()     deferfunc() {        panic(func()string {            return "defer panic"         })     }()     panic("panic") } 解析 考点:panic仅有最后一个可以被revover捕获 触发panic("panic")后顺序执行defer,但是defer中还有一个panic,所以覆盖了之前的panic("panic") 原文链接:https://blog.csdn.net/itcastcpp/article/details/80462619
剑曼红尘 2020-03-09 10:46:30 0 浏览量 回答数 0

回答

回 2楼(zc_0101) 的帖子 您好,       您的问题非常好,SQL SERVER提供了很多关于I/O压力的性能计数器,请选择性能计算器PhysicalDisk(LogicalDisk),根据我们的经验,如下指标的阈值可以帮助你判断IO是否存在压力: 1.  % Disk Time :这个是磁盘时间百分比,这个平均值应该在85%以下 2.  Current Disk Queue Length:未完成磁盘请求数量,这个每个磁盘平均值应该小于2. 3.  Avg. Disk Queue Length:磁盘请求队列的平均长度,这个每个磁盘平均值也应该小于2 4.  Disk Transfers/sec:每次磁盘传输数量,这个每个磁盘的最大值应该小于100 5.  Disk Bytes/sec:每次磁盘传入字节数,这个在普通的磁盘上应该在10M左右 6.  Avg. Disk Sec/Read:从磁盘读取的平均时间,这个平均值应该小于10ms(毫秒) 7.  Avg. Disk Sec/Write:磁盘写入的平均时间,这个平均值也应该小于10ms(毫秒) 以上,请根据自己的磁盘系统判断,比如传统的机械臂磁盘和SSD有所不同。 一般磁盘的优化方向是: 1. 硬件优化:比如使用更合理的RAID阵列,使用更快的磁盘驱动器,添加更多的内存 2. 数据库设置优化:比如创建多个文件和文件组,表的INDEX和数据放到不同的DISK上,将数据库的日志放到单独的物理驱动器,使用分区表 3. 数据库应用优化:包括应用程序的设计,SQL语句的调整,表的设计的合理性,INDEX创建的合理性,涉及的范围很广 希望对您有所帮助,谢谢! ------------------------- 回 3楼(鹰舞) 的帖子 您好,      根据您的描述,由于查询产生了副本REDO LOG延迟,出现了架构锁。我们知道SQL SERVER 2012 AlwaysOn在某些数据库行为上有较多变化。我们先看看架构锁: 架构锁分成两类: 1. SCH-M:架构更改锁,主要发生在数据库SCHEMA的修改上,从你的描述看,没有更改SCHEMA,那么可以排除这个因素 2. SCH-S:架构稳定锁,主要发生在数据库的查询编译等活动 根据你的情况,应该属于SCH-S导致的。查询编译活动主要发生有新增加了INDEX, 更新了统计信息,未参数化的SQL语句等等 对于INDEX和SQL语句方面应,我想应该不会有太多问题。 我们重点关注一下统计信息:SQL SERVER 2012 AG副本的统计信息维护有两种: 1. 主体下发到副本 2. 临时统计信息存储在TEMPDB 对于主体下发的,我们可以设置统计信息的更新行为,自动更新时,可以设置为异步的(自动更新统计信息必须首先打开): USE [master] GO ALTER DATABASE [Test_01]     SET AUTO_UPDATE_STATISTICS_ASYNC ON WITH NO_WAIT GO 这样的话查询优化器不等待统计信息更新完成即编译查询。可以优化一下你的BLOCK。 对于临时统计信息存储在TEMPDB里面也是很重要的,再加上ALWAYSON的副本数据库默认是快照隔离,优化TEMPDB也是必要的,关于优化TEPDB这个我想大部分都知道,这里只是提醒一下。 除了从统计信息本身来解决,在查询过程中,可以降低查询的时间,以尽量减少LOCK的时间和范围,这需要优化你的SQL语句或者应用程序。 以上,希望对您有所帮助。谢谢! ------------------------- 回 4楼(leamonjxl) 的帖子 这是一个关于死锁的问题,为了能够提供帮助一些。请根据下列建议进行: 1.    跟踪死锁 2.    分析死锁链和原因 3.    一些解决办法 关于跟踪死锁,我们首先需要打开1222标记,例如DBCC TRACEON(1222,-1), 他将收集的信息写入到死锁事件发生的服务器上的日志文件中。同时建议打开Profiler的跟踪信息: 如果发生了死锁,需要分析死锁发生的根源在哪里?我们不是很清楚你的具体发生死锁的形态是怎么样的。 关于死锁的实例也多,这里不再举例。 这里只是提出一些可以解决的思路: 1.    减少锁的争用 2.    减少资源的访问数 3.    按照相同的时间顺序访问资源 减少锁的争用,可以从几个方面入手 1.    使用锁提示,比如为查询语句添加WITH (NOLOCK), 但这还取决于你的应用是否允许,大部分分布式的系统都是可以加WITH (NOLOCK), 金融行业可能需要慎重。 2.    调整隔离级别,使用MVCC,我们的数据库默认级别是READ COMMITED. 建议修改为读提交快照隔离级别,这样的话可以尽量读写不阻塞,只不过MVCC的ROW VERSION保存到TEMPDB下面,需要维护好TEMPDB。当然如果你的整个数据库隔离级别可以设置为READUNCOMMINTED,这些就不必了。 减少资源的访问数,可以从如下几个方面入手: 1.    使用聚集索引,非聚集INDEX的叶子页面与堆或者聚集INDEX的数据页面分离。因此,如果对非聚集INDEX 操作的话,会产生两个锁,一个是基本表,一个是非聚集INDEX。而聚集INDEX就不一样,聚集INDEX的叶子页面和表的数据页面相同,他只需要一个LOCK。 2.    查询语句尽量使用覆盖INDEX, 使用全覆盖INDEX,就不需要访问基本表。如果没有全覆盖,还会通过RID或者CLUSTER INDEX访问基本表,这样产生的LOCK可能会与其他SESSION争用。 按照相同的时间顺序访问资源: 确保每个事务按照相同的物理顺序访问资源。两个事务按照相同的物理顺序访问,第一个事务会获得资源上的锁而不会被第二个事务阻塞。第二个事务想获得第一个事务上的LOCK,但被第一个事务阻塞。这样的话就不会导致循环阻塞的情况。 ------------------------- 回 4楼(leamonjxl) 的帖子 两种方式看你的业务怎么应用。这里不仅是分表的问题,还可能存在分库,分服务器的问题。取决与你的架构方案。 物理分表+视图,这是一种典型的冷热数据分离的方案,大致的做法如下: 1.    保留最近3个月的数据为当前表,也即就是我们说的热数据 2.    将其他数据按照某种规则分表,比如按照年或者季度或者月,这部分是相对冷的数据 分表后,涉及到几个问题: 第一问题是,转移数据的过程,一般是晚上业务比较闲来转移,转移按照一定的规则来做,始终保持3个月,这个定时任务本身也很消耗时间 再者,关于查询部分,我想你们的数据库服务器应该通过REPLICATION做了读写分离的吧,主库我觉得压力不会太大,主要是插入或者更新,只读需要做视图来包含全部的数据,但通过UNION ALL所有分表的数据,最后可能还是非常大,在某些情况下,性能不一定好。这个是不是业务上可以解决。比如,对于1年前的历史数据,放在单独的只读上,相对热的数据放在一起,这样压力也会减少。 分区表的话,因为涉及到10亿数据,要有好的分区方案,相对比较简单一点。但对于10亿的大表,始终是个棘手的问题,无论分多少个分区,单个服务器的资源也是有限的。可扩展性方面也存在问题,比如在只读上你没有办法做服务器级别的拆分了。这可能也会造成瓶颈。 现在很多企业都在做分库分表,这些的要解决一些高并发,数据量大的问题。不知是否考虑过类似于中间件的方案,比如阿里巴巴的TDDL类似的方案,如果你有兴趣,可以查询相关资料。 ------------------------- 回 9楼(jiangnii) 的帖子 阿里云数据库不仅提供一个数据库,还提供数据库一种服务。阿里云数据库不仅简化了基础架构的部署,还提供了数据库高可用性架构,备份服务,性能诊断服务,监控服务,专家服务等等,保证用户放心、方便、省心地使用数据库,就像水电一样。以前的运维繁琐的事,全部由阿里云接管,用户只需要关注数据库的使用和具体的业务就好。 关于优化和在云数据库上处理大数据量或复杂的数据操作方面,在云数据库上是一样的,没有什么特别的地方,不过我们的云数据库是使用SSD磁盘,这个比普通的磁盘要快很多,IO上有很大的优势。目前单个实例支持1T的数据量大小。陆续我们会推出更多的服务,比如索引诊断,连接诊断,容量分析,空间诊断等等,这些工作可能是专业的DBA才能完成的,以后我们会提供自动化的服务来为客户创造价值,希望能帮助到客户。 谢谢! ------------------------- 回 12楼(daniellin17) 的帖子 这个问题我不知道是否是两个问题,一个是并行度,另一个是并发,我更多理解是吞吐量,单就并行度而言。 提高并行度需要考虑的因素有: 1.    可用于SQL SERVER的CPU数量 2.    SQL SERVER的版本(32位/64位) 3.    可用内存 4.    执行的查询类型 5.    给定的流中处理的行数 6.    活动的并发连接数量 7.    sys.configurations参数:affinity mask/max server memory (MB)/ max degree of parallelism/ cost threshold for parallelism 以DOP的参数控制并行度为例,设置如下: SELECT * FROM sys.configurations WITH (NOLOCK) WHERE name = 'max degree of parallelism' EXEC sp_configure 'max degree of parallelism',2 RECONFIGURE WITH OVERRIDE 经过测试,DOP设置为2是一个比较适中的状态,特别是OLTP应用。如果设置高了,会产生较多的SUSPEND进程。我们可以观察到资源等待资源类型是:CXPACKET 你可以用下列语句去测试: DBCC SQLPERF('sys.dm_os_wait_stats',CLEAR) SELECT * FROM sys.dm_os_wait_stats WITH (NOLOCK) ORDER BY 2 DESC ,3 DESC 如果是吞吐量的话。优化的范围就很广了。优化是系统性的。硬件配置我们选择的话,大多根据业务量来预估,然后考虑以下: 1.    RAID的划分,RAID1适合存放事务日志文件(顺序写),RAID10/RAID5适合做数据盘,RAID10是条带化并镜像,RAID5条带化并奇偶校验 2.    数据库设置,比如并行度,连接数,BUFFER POOL 3.    数据库文件和日志文件的存放规则,数据库文件的多文件设置规则 4.    TEMPDB的优化原则,这个很重要的 5.    表的设计方面根据业务类型而定 6.    CLUSTERED INDEX和NONCLUSTERED INDEX的设计 7.    阻塞分析 8.    锁和死锁分析 9.    执行计划缓冲分析 10.    存储过程重编译 11.    碎片分析 12.    查询性能分析,这个有很多可以优化的方式,比如OR/UNION/类型转换/列上使用函数等等 我这里列举一个高并发的场景: 比如,我们的订单,比如搞活动的时候,订单刷刷刷地增长,单个实例可能每秒达到很高很高,我们分析到最后最常见的问题是HOT PAGE问题,其等待类型是PAGE LATCH竞争。这个过程可以这么来处理,简单列几点,可以参考很多涉及高并发的案例: 1.    数据库文件和日志文件分开,存放在不同的物理驱动器磁盘上 2.    数据库文件需要与CPU个数形成一定的比例 3.    表设计可以使用HASH来作为表分区 4.    表可以设置无序的KEY/INDEX,比如使用GUID/HASH VALUE来定义PRIMARY KEY CLUSTER INDEX 5.    我们不能将自增列设计为聚集INDEX 这个场景只是针对高并发的插入。对于查询而言,是不适合的。但这些也可能导致大量的页拆分。只是在不同的场景有不同的设计思路。这里抛砖引玉。 ------------------------- 回 13楼(zuijh) 的帖子 ECS上现在有两种磁盘,一种是传统的机械臂磁盘,另一种是SSD,请先诊断你的IO是否出现了问题,本帖中有提到如何判断磁盘出现问题的相关话题,请参考。如果确定IO出现问题,可以尝试使用ECS LOCAL SSD。当然,我们欢迎你使用云数据库的产品,云数据库提供了很多有用的功能,比如高可用性,灵活的备份方案,灵活的弹性方案,实用的监控报警等等。 ------------------------- 回 17楼(豪杰本疯子) 的帖子 我们单个主机或者单个实例的资源总是有限的,因为涉及到很大的数据量,对于存储而言是个瓶颈,我曾使用过SAN和SAS存储,SAN存储的优势确实可以解决数据的灵活扩展,但是SAN也分IPSAN和FIBER SAN,如果IPSAN的话,性能会差一些。即使是FIBER SAN,也不是很好解决性能问题,这不是它的优势,同时,我们所有DB SERVER都连接到SAN上,如果SAN有问题,问题涉及的面就很广。但是SAS毕竟空间也是有限的。最终也会到瓶颈。数据量大,是造成性能问题的直接原因,因为我们不管怎么优化,一旦数据量太大,优化的能力总是有限的,所以这个时候更多从架构上考虑。单个主机单个实例肯定是抗不过来的。 所以现在很多企业在向分布式系统发展,对于数据库而言,其实有很多形式。我们最常见的是读写分离,比如SQL SERVER而言,我们可以通过复制来完成读写分离,SQL SERVER 2012及以后的版本,我们可以使用ALWAYSON来实现读写分离,但这只能解决性能问题,那空间问题怎么解决。我们就涉及到分库分表,这个分库分表跟应用结合得紧密,现在很多公司通过中间件来实现,比如TDDL。但是中间件不是每个公司都可以玩得转的。因此可以将业务垂直拆分,那么DB也可以由此拆分开来。举个简单例子,我们一个典型的电子商务系统,有订单,有促销,有仓库,有配送,有财务,有秒杀,有商品等等,很多公司在初期,都是将这些放在一个主机一个实例上。但是这些到了一定规模或者一定数据量后,就会出现性能和硬件资源问题,这时我们可以将它们独立一部分获完全独立出来。这些都是一些好的方向。希望对你有所帮助。 ------------------------- 回 21楼(dt) 的帖子 问: 求大数据量下mysql存储,优化方案 分区好还是分表好,分的过程中需要考虑事项 mysql高并发读写的一些解决办法 答: 分区:对于应用来说比较简单,改造较少 分表: 应用需较多改造,优点是数据量太大的情况下,分表可以拆分到多个实例上,而分区不可以。 高并发优化,有两个建议: 1.    优化事务逻辑 2.    解决mysql高并发热点,这个可以看看阿里的一个热点补丁: http://www.open-open.com/doc/view/d58cadb4fb68429587634a77f93aa13f ------------------------- 回 23楼(aelven) 的帖子 对于第一个问题.需要看看你的数据库架构是什么样的?比如你的架构具有高可用行?具有读写分离的架构?具有群集的架构.数据库应用是否有较冷门的功能。高并发应该不是什么问题。可扩展性方面需要考虑。阿里云数据库提供了很多优势,比如磁盘是性能超好的SSD,自动转移的高可用性,没有任何单点,自动灵活的备份方案,实用的监控报警,性能监控服务等等,省去DBA很多基础性工作。 你第二个问题,看起来是一个高并发的场景,这种高并发的场景容易出现大量的LOCK甚至死锁,我不是很清楚你的业务,但可以建议一下,首先可以考虑快照隔离级别,实现行多版本控制,让读写不要阻塞。至于写写过程,需要加锁的粒度降低最低,同时这种高并发也容易出现死锁,关于死锁的分析,本帖有提到,请关注。 第三个问题,你用ECS搭建自己的应用也是可以的,RDS数据库提供了很多功能,上面已经讲到了。安全问题一直是我们最看重的问题,肯定有超好的防护的。 ------------------------- 回 26楼(板砖大叔) 的帖子 我曾经整理的关于索引的设计与规范,可以供你参考: ----------------------------------------------------------------------- 索引设计与规范 1.1    使用索引 SQL SERVER没有索引也可以检索数据,只不过检索数据时扫描这个表而异。存储数据的目的,绝大多数都是为了再次使用,而一般数据检索都是带条件的检索,数据查询在数据库操作中会占用较大的比例,提高查询的效率往往意味着整个数据库性能的提升。索引是特定列的有序集合。索引使用B-树结构,最小优化了定位所需要的键值的访问页面量,包含聚集索引和非聚集索引两大类。聚集索引与数据存放在一起,它决定表中数据存储的物理顺序,其叶子节点为数据行。 1.2    聚集索引 1.2.1    关于聚集索引 没聚集索引的表叫堆。堆是一种没有加工的数据,以行标示符作为指向数据存储位置的指针,数据没有顺序。聚集索引的叶子页面和表的数据页面相同,因此表行物理上按照聚集索引列排序,表数据的物理顺序只有一种,所以一个表只有一个聚集索引。 1.2.2    与非聚集索引关系 非聚集索引的一个索引行包含指向表对应行的指针,这个指针称为行定位器,行定位器的值取决于数据页保存为堆还是被聚集。若是堆,行定位器指向的堆中数据行的行号指针,若是聚集索引表,行定位器是聚集索引键值。 1.2.3    设计聚集索引注意事项     首先创建聚集索引     聚集索引上的列需要足够短     一步重建索引,不要使用先DROP再CREATE,可使用DROP_EXISTING     检索一定范围和预先排序数据时使用,因为聚集索引的叶子与数据页面相同,索引顺序也是数据物理顺序,读取数据时,磁头是按照顺序读取,而不是随机定位读取数据。     在频繁更新的列上不要设计聚集索引,他将导致所有的非聚集所有的更新,阻塞非聚集索引的查询     不要使用太长的关键字,因为非聚集索引实际包含了聚集索引值     不要在太多并发度高的顺序插入,这将导致页面分割,设置合理的填充因子是个不错的选择 1.3    非聚集索引 1.3.1    关于非聚集索引 非聚集索引不影响表页面中数据的顺序,其叶子页面和表的数据页面时分离的,需要一个行定位器来导航数据,在将聚集索引时已经有说明,非聚集索引在读取少量数据行时特别有效。非聚集索引所有可以有多个。同时非聚集有很多其他衍生出来的索引类型,比如覆盖索引,过滤索引等。 1.3.2    设计非聚集索引     频繁更新的列,不适合做聚集索引,但可以做非聚集索引     宽关键字,例如很宽的一列或者一组列,不适合做聚集索引的列可作非聚集索引列     检索大量的行不宜做非聚集索引,但是可以使用覆盖索引来消除这种影响 1.3.3    优化书签查找 书签会访问索引之外的数据,在堆表,书签查找会根据RID号去访问数据,若是聚集索引表,一般根据聚集索引去查找。在查询数据时,要分两个部分来完成,增加了读取数据的开销,增加了CPU的压力。在大表中,索引页面和数据页面一般不会临近,若数据只存在磁盘,产生直接随机从磁盘读取,这导致更多的消耗。因此,根据实际需要优化书签查找。解决书签查找有如下方法:     使用聚集索引避免书签查找     使用覆盖索引避免书签查找     使用索引连接避免数据查找 1.4    聚集与非聚集之比较 1.4.1    检索的数据行 一般地,检索数据量大的一般使用聚集索引,因为聚集索引的叶子页面与数据页面在相同。相反,检索少量的数据可能非聚集索引更有利,但注意书签查找消耗资源的力度,不过可考虑覆盖索引解决这个问题。 1.4.2    数据是否排序 如果数据需要预先排序,需要使用聚集索引,若不需要预先排序就那就选择聚集索引。 1.4.3    索引键的宽度 索引键如果太宽,不仅会影响数据查询性能,还影响非聚集索引,因此,若索引键比较小,可以作为聚集索引,如果索引键够大,考虑非聚集索引,如果很大的话,可以用INCLUDE创建覆盖索引。 1.4.4    列更新的频度 列更新频率高的话,应该避免考虑所用非聚集索引,否则可考虑聚集索引。 1.4.5    书签查找开销 如果书签查找开销较大,应该考虑聚集索引,否则可使用非聚集索引,更佳是使用覆盖索引,不过得根据具体的查询语句而看。 1.5    覆盖索引 覆盖索引可显著减少查询的逻辑读次数,使用INCLUDE语句添加列的方式更容易实现,他不仅减小索引中索引列的数据,还可以减少索引键的大小,原因是包含列只保存在索引的叶子级别上,而不是索引的叶子页面。覆盖索引充当一个伪的聚集索引。覆盖索引还能够有效的减少阻塞和死锁的发生,与聚集索引类似,因为聚集索引值发生一次锁,非覆盖索引可能发生两次,一次锁数据,一次锁索引,以确保数据的一致性。覆盖索引相当于数据的一个拷贝,与数据页面隔离,因此也只发生一次锁。 1.6    索引交叉 如果一个表有多个索引,那么可以拥有多个索引来执行一个查询,根据每个索引检索小的结果集,然后就将子结果集做一个交叉,得到满足条件的那些数据行。这种技术可以解决覆盖索引中没有包含的数据。 1.7    索引连接 几乎是跟索引交叉类似,是一个衍生品种。他将覆盖索引应用到交叉索引。如果没有单个覆盖索引查询的索引而多个索引一起覆盖查询,SQL SERVER可以使用索引连接来完全满足查询而不需要查询基础表。 1.8    过滤索引 用来在可能没有好的选择性的一个或者多个列上创建一个高选择性的关键字组。例如在处理NULL问题比较有效,创建索引时,可以像写T-SQL语句一样加个WHERE条件,以排除某部分数据而检索。 1.9    索引视图 索引视图在OLAP系统上可能有胜算,在OLTP会产生过大的开销和不可操作性,比如索引视图要求引用当前数据库的表。索引视图需要绑定基础表的架构,索引视图要求企业版,这些限制导致不可操作性。 1.10    索引设计建议 1.10.1    检查WHERE字句和连接条件列 检查WHERE条件列的可选择性和数据密度,根据条件创建索引。一般地,连接条件上应当考虑创建索引,这个涉及到连接技术,暂时不说明。 1.10.2    使用窄的索引 窄的索引有可减少IO开销,读取更少量的数据页。并且缓存更少的索引页面,减少内存中索引页面的逻辑读取大小。当然,磁盘空间也会相应地减少。 1.10.3    检查列的唯一性 数据分布比较集中的列,种类比较少的列上创建索引的有效性比较差,如果性别只有男女之分,最多还有个UNKNOWN,单独在上面创建索引可能效果不好,但是他们可以为覆盖索引做出贡献。 1.10.4    检查列的数据类型 索引的数据类型是很重要的,在整数类型上创建的索引比在字符类型上创建索引更有效。同一类型,在数据长度较小的类型上创建又比在长度较长的类型上更有效。 1.10.5    考虑列的顺序 对于包含多个列的索引,列顺序很重要。索引键值在索引上的第一上排序,然后在前一列的每个值的下一列做子排序,符合索引的第一列通常为该索引的前沿。同时要考虑列的唯一性,列宽度,列的数据类型来做权衡。 1.10.6    考虑索引的类型 使用索引类型前面已经有较多的介绍,怎么选择已经给出。不再累述。 ------------------------- 回 27楼(板砖大叔) 的帖子 这两种都可以吧。看个人的喜好,不过微软现在的统一风格是下划线,比如表sys.all_columns/sys.tables,然后你再看他的列全是下划线连接,name     /object_id    /principal_id    /schema_id    /parent_object_id      /type    /type_desc    /create_date    /modify_date 我个人的喜好也是喜欢下划线。    
石沫 2019-12-02 01:34:30 0 浏览量 回答数 0
阿里云企业服务平台 陈四清的老板信息查询 上海奇点人才服务相关的云产品 爱迪商标注册信息 安徽华轩堂药业的公司信息查询 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 天籁阁商标注册信息 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务 北京芙蓉天下的公司信息查询