#客户端请求头缓冲区大小,如果请求头总长度大于小于128k,则使用此缓冲区,
#请求头总长度大于128k时使用large_client_header_buffers设置的缓存区
client_header_buffer_size 128k;
#large_client_header_buffers 指令参数4为个数,128k为大小,默认是8k。申请4个128k。
large_client_header_buffers 4 128k;
当http 的URI太长或者request header过大时会报414 Request URI too large或400 bad request错误。
可能原因
场景1.cookie中写入的值太大造成的,因为header中的其他参数的size一般比较固定,只有cookie可能被写入较大的数据
场景2.请求参数太长,比如发布一个文章正文,用urlencode后,使用get方式传到后台。
当请求头过大时,超过large_client_header_buffer时,
nginx可能返回"Request URI too large" (414)或者"Bad-request"(400)错误,
如上例HTTP请求头由多行构成,
其中"GET http://www.264.cn/ HTTP/1.1"表示Request line
当Request line的长度大于large_client_header_buffer的一个buffer(128k)时,nginx会返回"Request URI too large" (414)错误,对应上面的场景2。
请求投中最长的一行也要小于large_client_header_buffer,当不是Request line的最长行大于一个buffer(128k)时,会返回"Bad-request"(400)错误,对应上面的场景1。
解决办法:这时可以调大上述两个值。
client_header_buffer_size 512k;
large_client_header_buffers 4 512k;
一.SQLite定义 简而言之,SQLite就是一款轻量级数据库,其占用资源非常低,支持SQL语法,遵循数据库的ACID 事务,SQLite数据库存储是Android系统提供的轻量级数据存储的方式之一。 二.创建数据库和数据表的步骤 1.新建类继承SQLiteOpenHelper; 2.实现构造方法; 3.重写onCreate方法; 4.重写onUpgrade方法; 5.实例化SQLiteOpenHelper的子类对象-MyDataBaseHelper; 6.点击事件中调用getReadableDatabase方法或getWritableDatabase方法。 三.创建数据库和表格实例(附代码) 在布局文件中创建一个Button按钮
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/create_btn" android:layout_width="match_parent" android:layout_height="50dp" android:text="create database"/> </LinearLayout> 新建类MyDataBaseHelper来继承SQLiteOpenHelper
public class MyDataBaseHelper extends SQLiteOpenHelper{//1.新建类继承SQLiteOpenHelper private Context context;//上下文 //数据库中创建一张Student表 public static final String Student = "create table Student (" + "id integer primary key autoincrement," + "name text," + "score real," + "age integer," + "gender text)"; //2.实现构造方法 public MyDataBaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { //int version-当前数据库的版本号,可用于对数据库进行升级操作 super(context, name, factory, version); this.
来源https://www.linuxidc.com/Linux/2016-09/135288.htm
####一、TCP服务的特点
#####传输层协议主要有两个:TCP协议和UDP协议。相对于UDP协议,TCP最主要的特点就是面向连接、字节流、和可靠传输。但是与UDP相比,TCP除了面向连接、字节流以外还有一些因为这些特性而带来的区别:
#####1、TCP协议的连接是一对一的,所以基于广播和多播的应用程序不能使用TCP服务,而无连接协议UDP则非常适合广播和多播;
#####2、由于TCP协议面向字节流服务,当发送端应用程序连续执行多次写操作时,TCP模块先将这些数据放入TCP发送缓冲区中,当TCP模块真正发送数据时,发送缓冲区中这些等待的数据可能被封装成一个或多个TCP报文段发出。因此,TCP模块发送出的TCP报文段的个数和应用程序执行的写操作次数之间没有固定的数量关系;而UDP则是发送端应用程序每执行一次写操作,UDP模块就将其封装成UDP数据报并发送。
#####3、TCP通过校验和,序列号,确认应答,重发控制,连接管理以及窗口控制等实现可靠性传输。首先,TCP协议采用发送应答机制,即发送端发送的每个TCP报文段都必须得到接收方的应答,才认为该TCP报文段传输成功;其次TCP协议采用超时重传机制,发送端在发送一个TCP报文段之后启动定时器,如果在定时间内未收到应答,则将重传该报文段;最后还有TCP报文段最终是以IP数据报发送的,而IP数据报到达接收端可能乱序,重复,所以TCP协议还会对接受到的TCP报文段重排、整理、再交付给应用层。
####TCP头部结构:
#####16目的和源端口号:告知主机该报文段是来自哪(源端口)以及传给哪个上层协议或应用程序(目的端口);
#####32位序号:一次TCP通信过程中某一个传输方向上的字节流的每个字节的变化;
#####32位确认号:用作对另一方发送来的TCP报文段的响应。确认号的值是收到的TCP报文段的序号值加1;
#####4位头部长度:标识该TCP头部有多少个4字节,4位所表示的最大值为15,所以整个TCP头部最长是60字节;
#####6位标志位:
#####①URG标志:表示紧急指针是否有效;
#####②ACK标志:表示确认号是否有效,携带ACK标志的报文段称为确认报文段;
#####③PSH标志:提示接收端应用程序应该立即从TCP缓冲区读走数据,为接受后续数据腾出空间;
#####④RST标志:表示要求对方重新建立连接,携带RST标志的TCP报文段称为复位报文段;
#####⑤SYN标志:表示请求建立一个连接,携带SYN标志的TCP报文段称为同步报文段;
#####⑥FIN标志:表示本端要关闭连接了,携带FIN标志的报文段称为结束报文段;
#####16位窗口大小:该窗口指的是接收通告窗口,告诉本端的TCP缓冲区还能容纳多少字节的数据,这样就可以控制发送数据的速度,实现流量控制;
#####16位校验和:由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏,该校验不仅包括TCP头部,还包括数据部分;
#####16位紧急指针:是一个正的偏移量,它和序号字段的值相加后表示最后一个紧急数据的下一字节的序号。
####TCP连接的建立和关闭
#####关于TCP的连接,之前利用Wireshark抓取过建立连接过程中的信息,可参考http://blog.csdn.net/sssssuuuuu666/article/details/79441513;可通过下图简单的回顾一下,很明显的可以看出一个连接的建立与断开正常过程至少需要来回发送7个包才能完成
#####补充一点:在建立TCP连接同时,也可确定发送数据报的单位,我们可以称其为“最大消息长度”(MSS:Max Segment Size)。TCP在传送大量数据时,是以MSS的大小将数据进行分割发送,进行重发时也同样是。在进行三次握手的时候,两端主机都分别告知对方自己的接口能够适应的MSS的大小,然后在挑选一个较小的值投入使用。
#####再介绍下TCP连接关闭的过程(四次挥手):
#####断开连接的过程是从报文段4开始的(很明显客户端首先发送了一个带FIN标志的报文段)。对应这个图来说:第一步客户端发送了一个带FIN的报文段,代表客户端要求关闭连接;;第二步服务器端发送报文段5来确认该结束报文;第三步客户端数据全部发送完成,发送一个带有FIN和ACK标志位的报文段,代表服务器端数据发送完成,也准备关闭,进入了最后的确认阶段;第四步客户端对于服务器端的关闭信息给予确认;
####半关闭状态
#####由于TCP连接是全双工的,所以允许两个方向的数据传输被独立关闭,所以在上面的图中可以看出当客户端发出结束报文给服务器端时,服务器并没有立即关闭,而是持续将未发送完的数据发送给客户端,直到服务器端也发送结束报文段才断开连接;这个中间的状态就称为半关闭;
####连接超时
#####对于提供可靠服务的TCP,面对当网络繁忙,或客户端访问一个距离它很远的服务器时,可能会导致服务器对于客户端发送出的同步报文段没有应答,此时客户端就会先进行重连(可能执行多次),如果重连无效,则通知应用程序连接超时。具体模拟场景可以参考《Linux高性能服务器编程》;从大佬们测试的结果可以看出当第一个发送的同步报文没有响应的时候,客户端发送了五个TCP报文段,时间间隔分别为1s、2s、4s、8s、16s,每次重连的超时时间都增加一倍,但是具体执行几次重连操作是由/proc/sys/net/ipv4/tcp_syn_retries 内核变量所定义的。
####TIME_WAIT状态
#####还是上面的插图,当客户端收到服务器的结束报文段之后,并没有立即进入CLOSED状态,而是转移到TIME_WAIT状态。在这个状态,客户端连接要等待一般长为2MSL(Max Segment Life报文段最大生存时间,一般建议值为2min)后才能关闭。
#####至于为什么要存在TIME_WAIT状态的原因有两点:
#####1、可靠的终止TCP连接:假设用于确认服务器结束的报文段丢失,那么服务器将重发结束报文段,所以客户端必须停留在某个状态以处理重复收到的结束报文段;
#####2、保证让迟来的TCP报文段有足够的时间被识别并丢弃:Linux系统中,一个TCP端口不能被同时打开多次(两次及以上)。当一个TCP连接处于TIME_WAIT状态时,我们便无法立即占用该连接占用着的端口来建立一个新连接;假设不存在TIME_WAIT状态,则应用程序能立即建立一个和刚关闭的连接相似的连接,新的化身可能会收到属于原来的连接的、携带应用程序数据的TCP报文段,显然这样是不应该发生的。至于TIME_WAIT状态要保持的时间选择为2MSL,则是因为2MSL时间可以确保网络上两个传输方向上尚未被接收到的、迟到的报文段都已经消失。从而可以确保在2MSL后,建立的新连接是安全的,绝对不会收到属于以前应用的数据。
TCP超时重传 #####TCP作为一个可靠的传输协议,当然也得保证在异常网络状况下,还能够控制数据传输可靠。所以TCP协议必须能够重传超时时间内未收到确认的TCP报文段。为此TCP模块为每个TCP报文段都维护了一个重传定时器,该定时器在TCP报文段第一次被发送时启动;如果超时时间内未接收到接收方的应答,TCP模块将重传TCP报文段并充值定时器,至于重传时间间隔以及执行多少次重传,就是TCP重传的策略;Linux系统中,对于在底层IP和ARP开始接管之前TCP最少执行3次重传,对于指定连接放弃前TCP最多可以执行的重传次数为15
####滑动窗口控制
#####TCP为了控制网络性能下降,引入了窗口的概念;窗口大小就是指无需等待而可以继续发送数据的最大值;也就是说发送端主机在发送了一个段以后不必要一直等待当前报文段的确认应答,而是继续发送;在下图中窗口大小为4个段。
#####下图白的部分即为窗口,在这窗口内的数据即便没有收到确认应答也可以发送出去;当发送端收到确认应答的情况下,才将窗口滑动到应答中的序列号的位置。
####拥塞控制
#####TCP模块还有一个重要的任务,就是提高网络利用率,降低丢包率,并保证网络资源对每条数据流的公平性,这就是所谓的拥塞控制。主要包括四个部分:慢启动,拥塞避免,快速重传和快速恢复。
#####拥塞控制的最终受控变量是发送端向网络一次连续写入的数据量,称之为发送窗口。不过发送端最终以TCP报文段来发送数据,所以发送窗口限定了发送端能连续发送的TCP报文段数量。发送端需要合理的选择发送窗口的大小,如果发送窗口太小,会引起明显的网络延迟,反之会导致网络拥塞。具体的拥塞处理方法可参考《Linux高性能服务器编程第三章》
以上内容参考自《Linux高性能服务器编程》《图解TCP/IP》
更生动的解释可以看看《图解TCP/IP》
1、使用placeholder读内存中的数据 最简单的一种方法是用placeholder,然后以feed_dict将数据给holder的变量,进行传递值。如下面代码所示:
from __future__ import print_function import tensorflow as tf import numpy as np x1 = tf.placeholder(tf.float32,shape=(3,2)) y1 = tf.placeholder(tf.float32,shape=(2,3)) z1 = tf.matmul(x1,y1) x2 = tf.placeholder(tf.float32,shape=None) y2 = tf.placeholder(tf.float32,shape=None) z2 = x2 + y2 # using feed_dict when placehoder with tf.Session() as sess: z2_value = sess.run(z2,feed_dict={x2:1,y2:2}) print(z2_value) rand_x = np.random.rand(3,2) rand_y = np.random.rand(2,3) z1_value,z2_value = sess.run( [z1,z2], # run together feed_dict={ x1:rand_x,y1:rand_y, x2:1,y2:2 } ) print(z1_value,z2_value) 2、使用queue读硬盘中的数据 参考如下的连接,不过感觉队列读取方式较为复杂,有了Dataset API后大部分不用此方法。
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("resources下的文件");
1、获取json文件列表
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("a.json");
String json = new String(IOUtils.readFully(inputStream, -1, true));
List<A> a = JSON.parseArray(json,A.class);
题意:用最少的不可交线段覆盖整个区间,求该最小值
课上摸鱼的时候没注意到题意的转换,写了没啥卵用的回文中心最长枚举,所以代码里的st和h/h2是几乎没用的
注意状态转移的时候不要只用最长线段去转移,这样未必最优(虽然没找出反例但是用st数组WA了一发)
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<string> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #define rep(i,j,k) for(register int i=j;i<=k;i++) #define rrep(i,j,k) for(register int i=j;i>=k;i--) #define erep(i,u) for(register int i=head[u];~i;i=nxt[i]) #define iin(a) scanf("%d",&a) #define lin(a) scanf("%lld",&a) #define din(a) scanf("%lf",&a) #define s0(a) scanf("%s",a) #define s1(a) scanf("%s",a+1) #define print(a) printf("%lld",(ll)a) #define enter putchar('\n') #define blank putchar(' ') #define println(a) printf("%lld\n",(ll)a) #define IOS ios::sync_with_stdio(0) using namespace std; const int maxn = 1e4+11; const int oo = 0x3f3f3f3f; const double eps = 1e-7; typedef long long ll; ll read(){ ll x=0,f=1;register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } char str[maxn]; int h[maxn],h2[maxn],st[maxn],dp[maxn]; bool ok[1111][1111]; int main(){ int T=read(); while(T--){ s1(str); int n=strlen(str+1); memset(ok,0,sizeof ok); rep(i,1,n)st[i]=0; rep(i,1,n){ h[i]=1; st[i-h[i]/2]=max(st[i-h[i]/2],h[i]); ok[i-h[i]/2][i-h[i]/2+h[i]-1]=1; int left=i-1,right=i+1; bool flag=0; while(!
对于爱装逼的人来说,电脑桌面图标摆放可不能随意。请看下面的示范:
如果你是老板的身份,那么可以考虑这样的桌面
《星球大战》粉丝的选择
IE是个可怕的东西,离我远点!
把桌面安排得像办公室一样,酷
也可以结合实景进行设置
选哪边?
“我想玩个游戏....”建议用在别人的电脑上
把桌面延伸到三维世界中,就无所谓图标怎么摆了
类似上面的玩法,如果你在大办公室里办公的话,可以考虑
想让别人觉得你神经病,不妨试试
图标不多,可以考虑“晾衣绳”方案
图标的摆放是一门艺术,真的
对于足球迷来说,这个太理想了
把桌面弄成这样一定是个细致的人
为了表明你恶搞达人和表情包斗士的身份,这个桌面很合适!
转自:大叔爱吐槽(id:dashuaitucao)
精彩回顾 点蓝字即可 ♡ 第一个就跪了!程序员专属表情包汇总之开发篇
♡ 女生节的一个分号,引发程序员的疯狂热议
♡ 程序员听到bug后的N种反应…
♡ 程序员相声:增删改查
♡ 女程序媛与男程序猿的一天
♡ 老说程序员如何看产品经理,今天说说产品经理讨厌哪些程序员
♡ 史上最深(sàng)入(xīn)浅(bìng)出(kuáng)的IT术语解读
♡ 如何假装成为一名好程序员?
这 是 一 个 伪 代 码!!!
写这篇文章的目的在于理解kd树在KNN算法中的应用, 弄清楚整个搜索和回溯过程
首先, 定义kd树结点的结构体
#include <stdio.h> typedef struct KD_Node { int kindex; //关键点直方图方差最大向量系列位置 int kvalue;//直方图方差最大向量系列中最中间模值 int n; //特征向量的维度 int leaf; //是否是叶子结点, 是则为1 struct KD_Node* left; //左孩子结点 struct KD_Node* right; //右孩子结点 struct Feature_Node* data; //特征向量 }KD_Node;然后, 定义一个函数, 这个函数的输入是一个kd树根节点和target(即待分类的样本) 输出是target在搜索过程中遇到的叶子结点
KD_Node* bitSearch(KD_Node kdtree, elemtype target, int k) { //进行二叉搜索, 找到target所在区域的叶子结点, k为维度 KD_Node* head = kdtree; int split_dim = kdtree->kindex; //初始的split维度 while(head->leaf == 0) //只要不是叶子结点 { if(target[split_dim]<=head->data[split_dim]) { head = head->left; } else { head = head->right; } }//此时head变成了叶子结点 min_dist = Dist(head, target);//求此时叶子结点与target之间的距离,并作为最小距离 return head; } 接着, 就是KNN的伪代码啦
在各种视频编码标准中,行业一直在求追“高压缩比(数据量越小越好)”,同时又保证“高视频质量”的算法。鱼和熊掌不可兼得,视频编码是一种折中的游戏。参数“视频码率”的设定,就代表了这种折中的选择。码率越高,数据量越大,视频质量越好,码率越小,数据量越小,视频质量越差。
但是,码率大到一定阈值之后,码率的提升带来的视频质量改善就会变得微不足道,所以这个码率阈值就显得非常重要。
网上这篇文章「Video Encoding Settings for H.264 Excellence」,就针对H.264视频编码,测试了不同视频分辨率下的码率阈值。
其介绍了用于高质量H.264视频编码的一组分辨率,码率设置,以及这些选择背后的推理。这篇文章很好的帮我们解答了:针对H.264视频编码(对其他视频编码格式无效),给定一个视频分辨率,要设置什么视频码率,才能得到“最具性价比”的高质量视频画面。
针对H.264编码格式,根据不同分辨率,推荐其对应的码率配置关系如下图所示:
宽屏 非宽屏
说实话,做这道题有被自己蠢到....
自己刚开始的想法是去用动态规划了,然而并没有自己想的关系那样简单。
而是!
运用了高中数学“二项式定理”“排列组合”的知识。。。。(我的心里奔过一万只....)
二项式定理:
Tk+1表示(a+b)n展开式的第k+1项,其通式为Tk+1=C(n,k)akb(n-k)。然后就可以解决了。
结合题意,这里的n即k,这里的k即a,这里的n-k即k-a=b
我的AC代码:
#include<iostream> #include<bits/stdc++.h> using namespace std; long long C[1010][1010]; int calculate(int k,int n) //计算C[k][n] { if(C[k][n]!=0) return C[k][n]; if(k==n || n==0) { C[k][n]=1; return C[k][n]; } C[k][n]=calculate(k-1,n)+calculate(k-1,n-1); //这里抓住组合数的“师傅去或不去”性质来递归求。 C[k][n]%=10007; return C[k][n]; } int main() { int a,b,k,n,m; cin>>a>>b>>k>>n>>m; calculate(k,n); long long res=C[k][n]; for(int i=0;i<n;i++) res=res*a%10007; for(int i=0;i<m;i++) res=res*b%10007; cout<<res; return 0; }
前端网页的js中的ajax请求,跳入了error,查了原因是json解析出错,经过调试,发现了json数据开头有个空白字符 \ufeff 原因是后台的包含的config.php文件带有bom格式的了,用notepad++打开代码文件可以得知的.把代码转化为无bom的utf8格式就正常了.
1、 首先切换到root用户 su root 获取root用户权限,当前工作目录不变(需要root密码) 2、在usr目录下建立java安装目录 cd /usr mkdir java 3、将jdk-8u60-linux-x64.tar.gz拷贝到java目录下(这里需要自己去官网下载java jdk 二进包) cp /mnt/hgfs/linux/jdk-8u60-linux-x64.tar.gz /usr/java/ 4、解压jdk到当前目录,得到文件夹 jdk1.8.0_* (注意:下载不同版本的JDK目录名不同!) tar -zxvf jdk-8u60-linux-x64.tar.gz 5、安装完毕为他建立一个链接以节省目录长度 ln -s /usr/java/jdk1.8.0_60/ /usr/jdk 6、编辑配置文件,配置环境变量 vim /etc/profile 在文本的末尾添加如下内容: JAVA_HOME=/usr/jdk CLASSPATH=$JAVA_HOME/lib/ PATH=$PATH:$JAVA_HOME/bin export PATH JAVA_HOME CLASSPATH 7、重启机器或执行命令 :source /etc/profile sudo shutdown -r now 8、查看安装情况 java -version 出现下面文字:证明已经成功 java version "1.8.0_60" Java(TM) SE Runtime Environment (build 1.8.0_60-b27) Java HotSpot(TM) Client VM (build 25.60-b23, mixed mode)
json_decode 返回NULL, 用json_last_error()取得的错误码是4,表示语法错误
用strlen判断出多了3个字符,于是用urlencode()函数转字符串为编码,看到字符串开头有3个字符\xEF\xBB\xBF, 是bom头,
用$content = trim($content, "\xEF\xBB\xBF");来转化一下,json_decode就输出正常的对象了.
广播由 发送广播和广播接收器两部分.无论是静态还是动态都需要在Manifest里申请权限,否则将会导致崩溃
动态加载
以广播网络状态为例
生成广播需要注册,需要两个参数 BroadcastReceiver和IntenFilter(筛选式Intent)
registerReceiver(networkChangeReceiver,intentFilter);//含义 广播接收器和筛选指定的广播 所以在Activity中定义一个BroadcastReceiver和IntentFilter.本文以NetworkChangeReceiver类来继承BroadcastReceiver并复写onReceiver方法.来生成BroadcastReceiver
public class MainActivity extends AppCompatActivity { private IntentFilter intentFilter;//筛选行Intent private NetworkChangeReceiver networkChangeReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentFilter=new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//网络变化是会发出之为这段字符串的广播,隐式Itent networkChangeReceiver=new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver,intentFilter);//注册广播需要一个(BroadcastReceiver,intentFilter). } class NetworkChangeReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { ConnectivityManager connectivityManager=(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();//此处如果报错,则可能没有申请权限 if (networkInfo != null && networkInfo.isAvailable()) { Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "network is unavailable"
举个例子说明引用是什么: a = 1 如上为一个简单的赋值语句,1就是对象,a就是引用,引用a指向对象1。 同理: b = 1 b也是对象1的引用。 通过内置函数id()返回对象的地址。 print id(a) #43220320 print id(b) #43220320 当我们创建多个等于1的引用时,实际上是让所有这些引用指向同一个对象。为了检验两个引用指向同一个对象,我们可以用is关键字。is用于判断两个引用所指向的对象是否相同。 print (a is b) #True 在Python中,整数和短小的字符,Python都会缓存这些对象,以便重复使用。赋值语句,只是创造了新的引用,而不是对象本身。长的字符串和其它对象可以有多个相同的对象,可以使用赋值语句创建出新的对象。每个对象都有存有指向该对象的引用总数,即引用计数(reference count)。 可以使用sys.getrefcount()获得引用计数,需要注意的是,当使用某个引用作为参数,传递给getrefcount()时,参数实际上创建了一个临时的引用。因此,getrefcount()所得到的结果,会比期望的多1。 from sys import getrefcount a = [ 1 , 2 , 3 ] print(getrefcount(a)) # 2 b = a print(getrefcount(b)) # 3 引用计数增加 1.对象被创建:x=4 2.另外的别人被创建:y=x 3.被作为参数传递给函数:foo(x) 4.作为容器对象的一个元素:a=[1, x, ‘33’] 引用计数减少 1.一个本地引用离开了它的作用域。比如上面的foo(x)函数结束时,x指向的对象引用减1。 2.对象的别名被显式的销毁:del x ;或者del y 3.对象的一个别名被赋值给其他对象:x=789 4.对象从一个窗口对象中移除:myList.remove(x) 5.窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。
原文地址:https://www.cnblogs.com/zwc1112/articles/8108758.html
表 是真实存在的,它占内存空间
视图 是虚拟表,不存储数据,存储的是sql,检索他的时候实际上是执行定义它的sql语句,不占任何内存
存储过程 理解的简单一点就是“数据库中的程序”,可以在不需要外部程序(如C,java,vb等)的情况下,让数据库自己解决复杂的、用一般sql不能实现
的功能,而视图则不然
表和视图的区别
视图不占实际空间,可以对任意的表进行叠加和剪裁,利用分区视图的功能,能加快表的I/O读取时间(需要2块以上硬盘)
视图和存储过程的区别
视图只不过是存储在sqlserver上的select语句罢了,当对视图请求时,sqlserver会像执行一句普通的select语句那样的执行视图的select语句,它的性能并 不像人们想象得那么出色。 而存储过程在编译后可以生成执行计划,这使得每次执行存储过程的时候效率将会更高,这是存储过程,另外台提交参数的时候,使用存储过程将会减少网络带宽流量,这是存储过程相对于普通的sql语句在性能上的最大的优势
存储过程和函数的区别
函数:只能返回一个变量的限制。而存储过程可以返回多个。
函数是可以嵌入在sql中使用的,可以在select中调用,而存储过程不行 执行的本质都一样。 函数限制比较多,比如不能用临时表,只能用表变量.还有一些函数都不可用等等.而存储过程的限制相对就比较少
1. 一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。
2. 对于存储过程来说可以返回参数,而函数只能返回值或者表对象。
3. 存储过程一般是作为一个独立的部分来执行,而函数可以作为查询语句的一个部分来调用,由于函数可以返回一个表对象,因此它可以在查询语句 中位于FROM关键字的后面。
4. 当存储过程和函数被执行的时候,SQL Manager会到PRocedure cache中去取相应的查询语句,如果在procedure cache里没有相应的查询语句,SQL Manager就会对存储过程和函数进行编译
UNet常见概念简介 Spawn:简单来说,把服务器上的GameObject,根据上面的NetworkIdentity组件找到对应监视连接,在监视连接里生成相应的GameObject.
Command:客户端调用,服务器执行,这样客户端调用的参数必需要UNet可以序列化,这样服务器在执行时才能把参数反序列化。需要注意,在客户端需要有权限的NetworkIdentity组件才能调用Command命令。
ClientRpc:服务端调用,客户端执行,同上,服务端的参数序列化到客户端执行,一般来说,服务端会找到上面的NetworkIdentity组件,确定那些客户端在监视这个NetworkIdentity,Rpc命令会发送给所有的监视客户端。
Server/ServerCallback:只在服务器端运行,Callback是Unity内部函数。
Client/ClientCallback:同上,只在客户端运行,Callback是Unity内部函数。
SyncVar:服务器的值能自动同步到客户端,保持客户端的值与服务器一样。客户端值改变并不会影响服务器的值。
上面的大部分特性都会转化成相应的MsgType,其中服务器调用,客户端执行对应MsgType有如Spawn,ClientRpc,SyncVar对应的MsgType分别为ObjectSpawn,Rpc,UpdateVars,这些都是NetworkServer调用,客户端得到相应消息,执行相应方法。客户端调用,服务器执行的MsgType有如Command,客户端发送,服务器检测到相应消息后执行。 UNet主要类介绍 NetworkIdentity组件介绍:网络物体最基本的组件,客户端与服务器确认是否是一个物体(netID),也用来表示各个状态,如是否是服务器,是否是客户端,是否有权限,是否是本地玩家等。一个简单例子,A是Host(又是服务器,又是客户端),B是一个Client,A与B分别有一个玩家PlayA与PlayB.在机器A上,playA与playB isServer为true,isClent为true,其中playA有权限,是本地玩家,B没权限,也不是本地玩家。在机器B上,playA与playB isServer为false,isClent为true,其中playB有权限,是本地玩家,A没权限,也不是本地玩家。A与B上的PlayA的netID相同,A与B上的PlayB的netID也相同,其中netID用来表示他们是同一网络物体在不同的机器上。 在下面用网络物体来表示带有NetworkIdentity组件的GameObject.
NetworkConnection:定义一个客户端与服务器的连接,包含当前客户端监视那些服务器上的网络物体,以及封装发送和接收到服务器的消息。
NetworkClient:主要持有当前NetworkConnection对象与所有NetworkClient列表的静态对象,处理一些默认客户端的消息。
网络物体上的监视者就是一个或多个NetworkConnection,用来表示一个或多个客户端对这个网络物体保持监视,那么当这个网络物体在服务器上更新后,会自动更新对所有监视者的对应的网络物体。
NetworkScene:简单来说,1Server与Client需要维护一个网络物体列表,Server可以遍历所有网络物体发送消息等,并且维持Server与Client上的网络物体保持同步,并且客户端记录需要注册的prefab列表.其中NetworkServer与ClientScene都包含一个NetworkScene对象,引用网络物体列表。
NetworkServer:主要持有一个NetworkScene并且做一些只有在服务器上才能对网络服务做的事,如spawn, destory等。以及维护所有客户端连接。
ClientScene:主要持有一个静态NetworkScene对象,用于注册网络物体的prefab列表,以及客户端场景上已经有的网络物体列表,处理SyncVar,Rpc,SyncEvent特性等,还有以及ObjectSpawn,objectDestroy,objectHide消息等。
UNet用时想到的问题 问题1 spawn发生了什么,客户端为什么要注册相应的prefab. 当服务器spawn一个网络物体时,网络物体调用OnStartServer,分配netID.并注册到相应服务器上的的NetworkScene的网络物体列表中,更新如isServer为true等信息。
查找所有客户端连接,查看每个客户端连接是否需要监视这个网络物体,如果为true,那么给这个客户端上一个消息MsgType.ObjectSpawn或是MsgType.ObjectSpawnScene(这种一般是服务场景变换后自动调用),并传递上面的netID.
当客户端接受到ObjectSpawn消息,会在注册的prefab里查找,查找到后Instantiate个网络物体,当接受到ObjectSpawnScene时,会在场景里查找这个网络物体,然后都注册到ClientScene里的NetworkScene的网络物体列表中,并更新netID与服务器的一样。更新如isClent为true等信息。我们手动spawn一个物体时,调用的是ObjectSpawn消息,客户端接到这个消息处理得到一个assetID,我们要根据prefabe实例一个新对象,只有客户端注册了相应的prefabe信息才能根据对应的assetID找到prefabe.
问题2 NetworkIdentity的netID表示什么,那个时候分配。 当服务器与客户端的netID相同,表示他们是同一物体,相应标示如SyncVar,服务器变了,对应客户端上相同的netID的网络物体,更新成服务器上的数据,Rpc,Commandg 一般也是相同的netID之间调用。
分配一般发生在服务器spawn一个网络物体时,网络物体调用OnStartServer时发生产生netID。
在客户端接受相应的ObjectSpawn消息,会把服务器上的对应物体的netID传递过来,产生新的网络物体并赋这个netID。
问题3 NetworkIdentity的sceneID是什么,在场景里已经有NetworkIdentity组件的物体是如何在客户端与服务器联系的。 当网络物体并不是spawn产生在服务器与客户端,而是在服务器与客户端场景本身就有时,我们也需要在服务器与客户端之间建立联系,这种物体会有一个sceneID来标示,这种模型一般是服务器场景变换完成后,NetworkServer调用spawnObjects会把这种网络物体与所有客户端同步,当spawn完成后过后,相应客户端会产生一个和服务端相同的netID。
问题4 服务器场景切换后,各个NetworkIdentity组件的物体如何与客户端联系。 如下顺序因为有异步操作,并不能确定,如下顺序只是一般可能的顺序。
服务器异步调用场景,发送给所有客户端开始切换场景。MsgType.Scene
客户端接受MsgType.Scene,开始切换场景。
服务器场景完成,会查找所有的网络物体,然后spawn这些网络物体,这样各个网络物体通过相同的netID联系起来。
客户端场景完成后,再次调用OnClientConnect,一般来说,不执行任何操作。
问题5 客户端为什么要网络物体的权限,它有了权限能做什么。 一般来说,当spawn某个服务器上的网络物体后,服务器有它的权限,客户端并不能更改这个网络物体,或是说更改这个网络物体相应的属性后并不能同步到服务器和别的客户端上,只是本机上能看到改变。
那么我如果需要能改变这个网络物体上的状态,并能同步到所有别的客户端上,我们需要拥有这个网络物体的权限,因为这样才能在本机上发送Command命令,才能告诉服务器我改变了状态,服务器也才能告诉所有客户端这个网络物体改变了状态。
其中本地player在创建时,当前客户端对本地player有权限。客户端上有权限的网络物体上的SyncVar改变后,也并不会能同步到服务器,服务器根本没有注册UpdateVars消息,这种还是需要客户端自己调用Command命令。
问题6 UNet常见的封装状态同步处理有那些,其中NetworkTransform与NetworkAnimator分别怎样通信,如果是客户端权限的网络物体又是怎么通信的了。 UNet常见的封装状态同步状态方法有二种。
一是通过ClientRpc与Command是封装发送消息。客户端与服务端一方调用,然后序列化相应的参数,然后到服务器与客户端反序列化参数执行。
二是网络内置的序列化与反序列化,序列化服务器的状态,然后客户端反序列化相应的值,如SyncVar通过相应的OnSerialize,OnDeserialize.这种只能同步服务器到客户端。
这二种本质都是客户端与服务器互相发送MsgType消息,对应的服务器与客户端注册相应消息处理。NetworkAnimator 服务器上的动画改变,会发消息通知所有客户端相应状态改变了,如Rpc。NetworkTransform 服务器通过OnSerialize序列化相应的值,然后客户端反序列化相应的值。
如果客户端有对应NetworkTransform与NetworkAnimator网络物体的权限。NetworkAnimator 相应客户端提交状态到服务器上,然后分发到所有客户端,相当于调用了Command,并在Command里调用了Rpc方法。NetworkTransform 相应客户端发送消息到服务器上,服务器更新相应位置,方向。然后通过反序列化到所有客户端。
所以如果客户端有授权,那么NetworkAnimator与NetworkTransform在服务器或是有授权的客户端的状态改变都能更新到所有客户端,注意这二个组件对localPlayerAuthority的处理不同,在NetworkTransform中,localPlayerAuthority为false时,客户端不能更新到所有客户端,在NetworkAnimator中,localPlayerAuthority为true时,服务器不能更新到客户端上。
其中注意SyncVar特性,就算客户端授权,客户端改变后,也不会同步到别的机器上。
所以如果我们自己设计类似的网络组件,需要考虑客户端授权的相应处理,就是差不多添加一个Command命令。
问题7 客户端授权与本地player授权有什么区别。 一般物体的权限都在服务器上,如果要对网络物体授权给客户端,一般通过SpawnWithClientAuthority实现,这样在相应客户端上的hasAuthority为true,其中相应的playerControllerID为-1。
而本地player授权localPlayerAuthority,在相应的网络物体上的Local Player Authority勾选上,在对这个网络物体的所有监视客户端上,本地player授权都是true,这种一般用于玩家,或是玩家控制位移的物体,playerControllerID大于等于0。
所以客户端授权针对是某个客户端,在这个客户端上的这个网络物体的hasAuthority为true,而本地player针对是某个网络物体,在所有客户端上的这个网络物体的localPlayerAuthority都为true.
问题8 UNet怎么实现迷雾地图 通过NetworkProximityChecker,这样每桢检测当前网络物体的监视连接,确定那些客户端需要这个网络物体。同样,想实现更复杂的可以自己实现类似。
个人博客网站文章地址:http://blog.mclink.xyz/index/article/index/id/24.html
对PHP oop编程的学习与认知。
1.使用Per-Class常量。
用途:可以在不需要初始化该类的情况下使用:
例子:
<?php class Man //定义Man类 { const birthday = 19960101; //定义常量变量 } //使用const修饰的变量,我们可以通过::操作符对其进行访问。例如: echo Man::birthday; //使用const修饰的变量是无法进行修改的,例如: // Man::birthday=19990101; //上面那句是会报语法错误的。 ?> 执行结果:打印出变量值 也就是19960101
2.对静态方法的实现
用途:PHP可以在方法前面使用static关键字,该方法就可以在未初始化类的情况下通过类名::来进行调用,类似于上面。例如:
<?php class Man //创建一个Man类 { static function boy() //创建静态方法 { return 'boy'; //函数返回字符串boy } } echo Man::boy(); //打印函数的返回值,也就是boy //但是在静态方法中,是不能使用this关键字的。因为可能会没有可以引用的对象实例 //通俗点说,就是一般我们调用函数是使用obj->method(),而$this就是当前的对象,但是因为 //我们没有对类进行进行实例化,也就没有所谓的对象,故不能使用。 ?> 3.延迟静态绑定
从PHP5.3版本引入了延迟静态绑定(last static binding)的概念。
用途:允许在一个静态继承的上下文中对一个被调用类的引用。父类可以使用子类重载的静态方法。例如:
<?php class father //father类 { public static function who() { echo __CLASS__;//__CLASS__作用是当前的类名,此处打印出father } public static function test() { static ::who();//进行静态绑定 } } class son extends father//son类继承father类 { public static function who() { echo __CLASS__; //打印 出son } } son::test(); //结果是打印出son.
Java基础知识梳理(详细) 1. Java中的数据类型 基本数据类型特征表
类型位数最小值最大值默认值其他byte8-128(-2^7)127(2^7-1)0有符号、二进制补码表示short16-32768(-2^15)32767(2^15-1)0有符号、二进制补码表示int32-2^312^31-10有符号、二进制补码表示long64-2^632^63-10L(0l)有符号、二进制补码表示float322^(-149)2^128-10.0f单精度、IEEE754标准double642^(-1074)2^1024-10.0d双精度、IEEE754标准char16\u0000(0)\uffff(65535)\u0000(0)单一的、Unicode字符 字符类型涉及到编码问题。
char类型固定为16位2字节长,因为java内码表示字符按照UTF-16存储。而一旦转化为字节就要根据特定的编码格式来看了,例如UTF-8占用1-4字节。出现乱码问题需要分析编码,在windows系统下默认的编码是GBK,使用gradle命令行可能出现乱码(还没发现啥解决办法)。关于字符的一个问题是char是否能表示所有的汉字,我觉得是不能的,可能可以表示常用的所有汉字,但生僻字16位肯定不够的,不然也不至于需要UTF-8多达4个字节来表示汉字。
String内部是通过char数组实现的,生僻字可能需要两个char来表示。
Unicode是一种编码规范,有Unicode编码表,其具体实现有UTF-8, UTF-16, UTF-32等。除此之外还有GBK,GB2312等。
ASCII编码占8位,一个字节就可以表示英文环境所有字符。
引申到MySQL建表过程中需要指定编码,如果是utf8编码可以留意下,一个字符占据可变字节长度,varchar(10)表示的是10个字符而非字节。
GB2312收录了约7000常用汉字,GBK收录了20000+汉字。相关的文章很多,也不是很容易分辨,这里我只列一下结论:GB2312和GBK都继承自ASCII编码,即英文和符号编码和ASCII一致;对于汉字的编码则一律用2字节,能够表示的范围有所不同。而UTF-8编码是1-4字节,汉字绝大多数用3字节表示。
浮点数内存结构
类型位数符号位指数位尾数位float321823double6411152 原始数据类型对应的封装对象
(byte, Byte), (short, Short), (long, Long), (float,Float), (double, Double), (boolean, Boolean)(int, Integer), (char, Character) 【小题】
Integer i = null; int j = i.intValue(); 【答案】编译通过,但运行时报错NullPointerException。
自动装箱和拆箱
Integer i = 100; //自动装箱,编译器执行Integer.valueOf(100) int j = i; //自动拆箱,编译器执行i.intValue() 由于自动拆装箱的存在,要小心留意i为null。
【小题】
Integer i1 =200; Integer i2 =200; System.out.println("i1==i2: "+(i1==i2)); Integer i3 =100; Integer i4 =100; System.out.println("i3==i4: "